• Runtimes
  • getting animation working with libgdx runtime

Related Discussions
...

Hi Guys,
I have been playing about with the spine runtime for a week or two now…and im still having problems getting the animations working correctly.
I can’t seem to get the walking, running and jumping to occur when I want to…I was hoping you could help. Im using the spineboy atlas and json file. I have had a look at the example and and the way you animate there looks different to the way you animate in super spineboy (maybe I need to read the code again in more detail to figure it out).

I have a player class which extends a gameobject class which contains all my movement logic. The player class essentially has 3 methods, setup, update, render and a method which tracks movement state. Im not sure where the best place is to place the animation code? In the update method or the movement state method.
The code doesn’t play the walk animation when its meant to or run when its meant to…im getting a little lost and perhaps am missing something simple. Im not sure where I am supposed to track the time element for the animation…
I have given my a sample of my code below to help understand where im making mistakes.
hope the question makes sense...

public class Player extends GameObject {

//declare spine variables
public TextureAtlas atlasSpine;
public Skeleton skeleton;
public AnimationState animState;
public SkeletonJson json;
public SkeletonData skeletonData;
public AnimationStateData animStateData;
public SkeletonRenderer renderer;

public Player() {

    setup();
}

public void setup() {
	renderer = new SkeletonRenderer();
	renderer.setPremultipliedAlpha(false);
	atlasSpine = new TextureAtlas(Gdx.files.internal("spineboy/spineboy.atlas"));
	json = new SkeletonJson(atlasSpine);
	json.setScale(0.5f); 
	skeletonData = json.readSkeletonData(Gdx.files.internal("spineboy/spineboy.json"));

	animStateData = new AnimationStateData(skeletonData);
	animStateData.setDefaultMix(0.2f);

	setMix(animStateData, "idle", "run", 0.3f);
	setMix(animStateData, "run", "idle", 0.1f);
	setMix(animStateData, "walk", "run", 0.3f);
	setMix(animStateData, "run", "walk", 0.2f);
	setMix(animStateData, "jump", "jump", 0);
	//etc 

}
public void update(deltaTime) {
	//……..
	//some code to check direction…
	//……..
	if ((velocity.x > 0.0f) && (velocity.x < 6.0f)) {
		animState.setAnimation(0, "walk", true);
		movestate = “WALKING”

	}
	
	if ((velocity.x > 6.0f) && (velocity.x < (terminalVelocity.x))) {

		animState.setAnimation(0, "run", true);
		movestate = “RUNNING”

	}
	//….
	//more of the same code
	//….

	animState.update(stateTimeSpine);
	super.update(deltaTime);
}

public void render() {
	skeleton.setPosition(position.x, position.y);
	animState.apply(skeleton); // Poses skeleton
	skeleton.updateWorldTransform(); 
	renderer.draw(batch, skeleton); 
	//I have renderer class which calls this render method hence why batch.begin and end are
	//not included in this method.
}

public void movementState(MoveState movestate) {
switch (movestate) {
    case STANDING:
    
    case JUMPING:
    
    case WALKING:
	//animState.setAnimation(0,"walk",false); //do I call it here?? Have //tried it but it doesn’t work correctly
    case RUNNING:
	
    default:
	
}

}

There are a few key points
(1) When you call setAnimation, it starts the animation from the beginning. So when it's called every update, the animation starts from the beginning at every frame. This makes it look like the animation isn't moving.

(2) The MoveState type isn't defined in this code. I assume it's an enum, or something else. You seem to be treating it as a string in other places. (or whatever. I don't use Java these days.) But based on the switch block, that's likely to store what state your character is in. Under a certain pattern of programming, MoveState can be used to detect when your character changes state, by storing the previous state and checking if it matches the intended state.

So, for example, if your character is already running, you shouldn't be calling setAnimation(0, run, true) or else it would go back to the first frame.
But if he's doing something else, that's the right time to call setAnimation.

Pharan's advice is good. I'll also say that it is a good idea to separate your model from your view. See how Super Spineboy does it. The model has all the state that makes up the game information, but doesn't know anything to do with drawing it. That means it doesn't have references to textures, etc. The view knows about the model and knows how to render that data. The model does not know about the view. This separation keeps your code clean, otherwise it is easy to make a tangled mess.

Thanks for the constructive advice Pharan, Nate, very much appreciated! taking your comments a little further...

(1) and (3) so do you need to do something like this:

if (buttonPressed) {
	animState.setAnimation(0, "walk", true);
}
else {
	animState.setAnimation(0, "walk", false);
}

will the above work? while the button is pressed the animation keeps going and then as soon as its release the animation will come to a stop. can you give an example which i can use to test?

and then also have a statement like this in the setup method

setMix(animStateData, "walk", "walk", 0.3f);
setMix(animStateData, "walk", "idle", 0.3f);

this im guessing will smooth the animation.

how else do you go from one animation to another with out it looking too jerky. is the only method via setmix method?

i guess once i get past this road bump i will want to have more granular control as i progress further with my code. Are there other methods i could use to control animation with? (i will reread the documentation...i find it dont focus on the other stuff till i have the basics working)

(2) yes MoveState is an enum...i just used a string to for convience in the code sample. although i guess it wasnt that convienient...i will have a think about how to use this properly. As the the number of animations i want to manage will probably be around 30; and currently im struggling to get 3 working together... :S

Thanks for your comments Nate i will try and seperate it all...i just want to get it working first...i will tidy it all up!
besides whats wrong with having each gameobject being self contained? they all have an update method and a render method. the code to update the objects is done via the update method and the code to render it in the render method? makes it very easy to keep track of i think...
i plan on moving all the references to the textures to an asset class so that will also move things towards an MVC pattern.

It seems you are reading method names and trying to guess what the method does. Read the documentation and understand the API calls you are making. Eg, the boolean passed to setAnimation is whether the animation is looping, not whether it is being applied. Create a simple application that only displays a skeleton. Next, learn how to apply an animation. Next, learn how to interrupt an animation with another. Next, learn how to set mix times so the interruption smoothly mixes from one animation to the next. spine-libgdx comes with examples for all of this.

You can combine your model and view, it's an organizational choice. One issue with doing that is that it becomes difficult to serialize your game state.

i get that nate, what i was trying to achieve was when user lets go of a movement button the animation goes from the looping version...to a non looping version of the animation. ok i'll reread the documentation and pay a bit more attention. was just trying to short cut things a little but i guess there isnt a substitute for a little bit of effort and work! 🙂

Usually you would go from a run animation to an idle animation when the user lets go of the run button. To do that you just set the animation to idle. You can use a mix time so the animation time isn't instant.