Hello Everyone,
I'm having a weird problem here, I followed the documentation and I'm still having problem with my character's animation, it stuck on the first frame of it's animation, even thought my app's lifecycle is working perfectly (I hope :giggle๐.
- Using in Gradle, spine-libgdx:3.5.51.1
- Character uses skins and meshes - all are visible and working both in RunTime & Editor.
- Animations work in the Editor.
- Exporting using JSON, Atlas and PNG
- Using Ashely
- There are no crashes or Exceptions thrown.
CharacterBuilder.java
This class builds GameObject which I use to update and render Skeletons, SpineData is just a POJO that holds Spine information accessable for my RenderSystem, I checked and this build() function is called only once (for testing of course)
public GameObject build() throws CharacterBuilderException {
/* Loading a SpineData */
SpineData spineData = SpineDataLoader.getDefault().loadFromAssets(fileName);
/* Don't create Characters without graphics */
if (spineData == null) {
throw new CharacterBuilderException("[!] CharacterBuilder couldn't load FileName: \"" + String.valueOf(fileName) + "\"");
}
/* In some cases load skin is mandatory or else nothing will be rendered */
if (skinName != null) spineData.getSkeleton().setSkin(skinName);
GameObject entity = new GameObject(x, y, z, spineData);
/* Space for adding beyond basic Components */
AnimationState state = spineData.getAnimationStateData();
state.setAnimation(0, "Standing", false);
state.addAnimation(0, "WalkingStart", false, 2);
state.addAnimation(0, "Walking", true, 0);
/* to test if it runs only once */
System.out.println("CharacterBuilder.build()");
return entity;
}
RenderSystem.java
This class is for rendering on screen, it gets updated by Ashley life cycle, this is the only place that draws anything on screen, please check the update() method.
import com.badlogic.ashley.core.*;
import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
import com.esotericsoftware.spine.AnimationState;
import com.esotericsoftware.spine.Skeleton;
import com.esotericsoftware.spine.SkeletonMeshRenderer;
import com.esotericsoftware.spine.SkeletonRendererDebug;
import com.yuststudio.meanspace.core.components.basic.PositionComponent;
import com.yuststudio.meanspace.core.components.basic.RenderableComponent;
import com.yuststudio.meanspace.core.model.SpineData;
import com.yuststudio.meanspace.core.mappers.Mapper;
import java.util.*;
public class RenderSystem extends EntitySystem implements EntityListener {
/**
* Simple Array List of z sorted Entities
*/
private List<Entity> zOrderArray;
private SkeletonMeshRenderer renderer;
private SkeletonRendererDebug debugRenderer;
private Family renderFamily;
private PolygonSpriteBatch batch;
public RenderSystem(PolygonSpriteBatch batch, SkeletonMeshRenderer renderer, SkeletonRendererDebug debugRenderer) {
this.batch = batch;
this.renderer = renderer;
this.debugRenderer = debugRenderer;
}
private int size;
private Entity entity;
private SpineData spineData;
private PositionComponent pos;
private RenderableComponent renderableComponent;
/[i].................................................Public.Methods.................................................[/i]/
/**
* Updates Spine Skeleton's positions and draws everyone on screen
*
* @param deltaTime
*/
@Override
public void update(float deltaTime) {
/* Sort only if Z was modified by someone */
if (PositionComponent.s_Z_Modified) {
sort();
PositionComponent.s_Z_Modified = false;
}
/* Drawing using Z order */
batch.begin();
size = zOrderArray.size();
for (int i = 0; i < size; i++) {
entity = zOrderArray.get(i);
pos = Mapper.position.get(entity);
if (pos != null) {
renderableComponent = Mapper.renderable.get(entity);
spineData = renderableComponent.getSpineData();
if (spineData != null) {
Skeleton skeleton = spineData.getSkeleton();
skeleton.setX(pos.getX());
skeleton.setY(pos.getY());
AnimationState state = spineData.getAnimationStateData();
state.update(deltaTime);
state.apply(skeleton);
skeleton.updateWorldTransform();
renderer.draw(batch, skeleton);
}
}
}
batch.end();
}
/[i]................................................Adders.Removers.................................................[/i]/
@Override
public void addedToEngine(Engine engine) {
renderFamily = Family.all(PositionComponent.class, RenderableComponent.class).get();
zOrderArray = new ArrayList<Entity>();
engine.addEntityListener(renderFamily, this);
}
@Override
public void removedFromEngine(Engine engine) {
engine.removeEntityListener(this);
}
/[i]................................................Entity.Listener.................................................[/i]/
@Override
public void entityAdded(Entity entity) {
zOrderArray.add(entity);
sort();
}
@Override
public void entityRemoved(Entity entity) {
zOrderArray.remove(entity);
}
/[i]................................................Private.Methods.................................................[/i]/
private static final Comparator comparator = new Comparator<Entity>() {
@Override
public int compare(Entity o1, Entity o2) {
return (int) Math.signum(
Mapper.position.get(o1).getZ() - Mapper.position.get(o2).getZ()
);
}
};
private void sort() {
Collections.sort(zOrderArray, comparator);
}
}
SpineData.java
public class SpineData implements Cloneable{
private TextureAtlas atlas;
private Skeleton skeleton;
private AnimationState animationState;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public SpineData(TextureAtlas atlas, Skeleton skeleton) {
this.atlas = atlas;
this.skeleton = skeleton;
}
public SpineData(TextureAtlas atlas, Skeleton skeleton, AnimationState animationState) {
this.atlas = atlas;
this.skeleton = skeleton;
this.animationState = animationState;
}
public TextureAtlas getAtlas() {
return atlas;
}
public Skeleton getSkeleton() {
return skeleton;
}
public void setAnimationStateData(AnimationState animationState) {
this.animationState = animationState;
}
public AnimationState getAnimationStateData() {
return animationState;
}
}
Loading Image
It just stuck on the animation's first frame, if I change the deltaTime in the state.update(deltaTime); manually then it's stuck on a different frame, seems like state.getCurrent(0).getTrackTime() does increment but the animation doesn't happen anyway... I use InputProcessor to move this guy around and that works so the life cycle's functional.
I probably did something silly or missed something, wasted too much time on this, need some help from the pros, help will be most appreciated! :notme:
Thank you for your time hope we solve this quickly! :beer: