Animating Sprites

Before starting, add the indexes for your character’s walking animation’s beginning and your animation’s end to your Constants class. For the sprite below there are only 2 frames of the walking animation. For the Mario sprite, there are only 4 frames of animation.

For this SpriteSheet, there are only 2 walking animation frames.
Mario has 4 frames, the last frame is the beginning of another animation.
//movement animation sprites
public static final int RUN_ANIM_STRT = 1;
public static final int RUN_ANIM_END = 4;

Afterward, add these variables to the Player class. This will hold the animation frames in an ‘Array’-like object called ‘Animation’. The Animation object will hold your running animation and the singular TextureRegion will hold your jump texture. In my demo game, the jump animation only has one frame, but if your character has multiple frames for their jump, feel free to change the TextureRegion into another Animation object.

Then you want to add 2 more variables to help you manage your States. Previously, I mentioned States as a way to track what your player is currently doing. Now you want a ‘previousState’ variable to track what the last state was and also a ‘stateTimer’ to track the time. ‘stateTimer’ will allow you to run the animation smoothly. You should also add the states JUMPING and RUNNING to your ‘State’ enum.

//animation texture regions
private Animation<TextureRegion> runAnimation;
private TextureRegion jumpAnimation;

//state management
public State previousState;
private float stateTimer;
public enum State {STANDING, JUMPING, RUNNING};

Initialize your State management variables, by setting the initial previousState to STANDING and the animation timer ‘stateTimer’ to 0.

previousState = State.STANDING;
stateTimer = 0;

Create an Array of TextureRegions called frames and then create a ‘for’ loop that will go through your run animation’s frames. (Use the numbers you added in your Constant’s page) Then, inside the ‘for’ loop, you’ll add a frame of your animation to the Array called ‘frames’ by creating a new TextureRegion through calling the Atlas and getting a specific region. Make sure you specify what region you want using your region names in your Constants class. Then because all your sprites are 16 pixels, you can index how many tiles your images are apart. Finally, you can create the Animation object by passing in the frame duration (how long each frame is) and the Array ‘frames’. Then clear the frames Array so you can reuse it if you need more animations. Since my jumpAnimation is just 1 frame, I can just set the frame. But if you have a multi-frame animation for your jump you can just copy the same steps for the runAnimation.

The other way to add animation frames is to simply call ‘frames.add(…)’ for each frame you have and input the values for each frame.

Array<TextureRegion> frames = new Array<TextureRegion>();

for(int i = Constants.RUN_ANIM_STRT; i < Constants.RUN_ANIM_END; i++)
{
frames.add(new TextureRegion(screen.getAtlas().findRegion(Constants.PLAYER_STRING), i * 16, 0, 16, 16));
}
runAnimation = new Animation<>(0.1f, frames);
frames.clear();

jumpAnimation = new TextureRegion(screen.getAtlas().findRegion(Constants.LITTLE_MARIO_STRING), 80, 0, 16, 16);

In your getFrames() method, you should add a case for JUMPING and RUNNING to your switch case like below. If a State uses an animation instead of just a frame like the RUNNING case does, you should set the region to your Animation object and call getKeyFrames(), make sure to pass in your stateTimer and a boolean for if you want your animation to loop.

switch(currentState)
        {
//add the code from here...
            case JUMPING:
                region = jumpAnimation;
                break;
            case RUNNING:
                region = runAnimation.getKeyFrame(stateTimer, true);
                break;
//to here.
            case STANDING:
            default:
                region = playerIdleTexture;
                break;
        }

Then update your stateTimer in your getFrame() method. If the currentState is equal to the previousState, then that means the same animation is still running. If that’s true then simply add deltaTime to your original stateTimer. Otherwise, if the states are different, that means the animation has ended and you can reset the stateTimer to 0. Finally, set the previousState equal to the currentState.

//after checking if the image needs to be flipped
if(currentState == previousState) {
        stateTimer = stateTimer + deltaTime;
} else {
        stateTimer = 0;
}

previousState = currentState;

The last thing to do is update getState(). To check if your player is JUMPING, check if your body’s linear velocity is greater than 0 in the ‘y’ direction, this means they’re in the air. The other part is if the player is moving in the negative direction along the ‘y’ axis and was previously jumping, this means that they are still jumping but now they’re on their way back down. For RUNNING, just check if the player is moving in either direction along the ‘x’-axis.

public State getState() {
        if(box2Body.getLinearVelocity().y > 0 || box2Body.getLinearVelocity().y < 0 && previousState ==    
        State.JUMPING)
        {
              return State.JUMPING;
        }
        else if(box2Body.getLinearVelocity().x != 0)
        {
             return State.RUNNING;
        }
        return State.STANDING;
    }

After running your app, you should see your animated sprite!

Video Lesson