Intoduction
When we need to animate our game objects, one of the methods we have is the frame by frame animations. It’s the classic animation method, and consists on drawing a serie of images that, when they are showed in sequence, it seems the element is doing some action.
For example, if we want to show a running character, we should have a serie of images, each with a little advance over the previous image, so as when they are displayed them sequentially, we can see the character moving:
Frame by frame animations in LibGDX
La Animation class
The class responsible of the management of frame by frame animations is Animation. Its work involves in calculate the frame that must rendered at each time, being us the responsibles of draw the result.
This class needs these four elements to work:
- Images that compose the animation. Each of this images is a frame of the animation.
- Time to wait between a frame and the next one.
- Play mode. The possible modes are defined in the enum
Animation.PlayMode. It tells to ourAnimationobject the order in which the frames must be rendered. The possible modes are:NORMAL: The frames are displayed from first to last. Without looping. So when the animation gets to the last frame, then always is returned the last frame.REVERSED: The frames are displayed from last to first. Without looping. So when the animation gets to the first frame, then always is returned the first frame.LOOP: The frames are displayed from first to last. With looping. So when the animation gets to the last frame, then starts again with the first one.LOOP_REVERSED: The frames are displayed from last to first. With looping. So when the animation gets to the first frame, then starts again with the last one.LOOP_PINGPONG: The frames are displayed from first to last. When it gets to the last one, it starts to draw from last to first, and then again from first to last, last to first, …, ping pong 🙂LOOP_RANDOM: The frames are displayed randomly, without a defined order.
- Elapsed time from the beginning of the animation. Each time we draw on screen, we must pass the elapsed time to the
Animation, and it return us the frame to draw depending on the elapsed time and the play mode.
Example
Normally, in videogames, each character will have several animations which will be drawn depending of character’s state (walking, running, jumping, etc.). In order to make this example the most clear possible, I will not use states, and I am going to show only one element with one animation.
Images
For this example i’m going to use the file (charset.png) which stores all the images that compose the animation:
Also I will make the file charset.atlas, knowing that each frame takes 80 pixels for width and 120 for height. In the atlas, I use the same name for all the frames, and I assign an index to each one of them. The file looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | charset.png format: RGBA8888 filter: Linear,Linear repeat: none running rotate: false xy: 0, 0 size: 80, 120 orig: 80, 120 offset: 0, 0 index: 0 running rotate: false xy: 80, 0 size: 80, 120 orig: 80, 120 offset: 0, 0 index: 1 running rotate: false xy: 160, 0 size: 80, 120 orig: 80, 120 offset: 0, 0 index: 2 (continue ...) |
This way, we can easily get all frames that compose the animation:
public class GdxAnimationExample extends ApplicationAdapter { ... // Atlas with all the frames defined in "charset.atlas" private TextureAtlas charset; ... @Override public void create () { ... // Frames loading from "charset.atlas" charset = new TextureAtlas( Gdx.files.internal("charset.atlas") ); // Getting the images for "running" animation Array<atlasregion> runningFrames = charset.findRegions("running"); ... } ... } </atlasregion> |
Building the animation
Once we have loaded the images that compose the animation, we can build it. For this example we want to play it for ever, so we use the play mode PlayMode.LOOP:
public class GdxAnimationExample extends ApplicationAdapter { ... // Time which each frame keeps on screen private static float FRAME_DURATION = .05f; // Running animation private Animation runningAnimation; ... @Override public void create () { ... // Building of the animation runningAnimation = new Animation(FRAME_DURATION, runningFrames, PlayMode.LOOP); ... } ... } |
Drawing each frame
At the time to draw, the object runningAnimation will return us the frame that we need to draw depending of the elapsed time. For this reason we have a local variable, elapsed_time, where we store the elapsed time from de beginning of the animation:
public class GdxAnimationExample extends ApplicationAdapter { ... // Frame that must be rendered at each time private TextureRegion currentFrame; // Elapsed time private float elapsed_time = 0f; // Auxiliar variables to know where to draw the picture to center it on the screen private float origin_x, origin_y; ... @Override public void render () { ... // Elapsed time elapsed_time += Gdx.graphics.getDeltaTime(); // Getting the frame we must draw at this moment currentFrame = runningAnimation.getKeyFrame(elapsed_time); // Drawing on the screen batch.begin(); batch.draw(currentFrame, origin_x, origin_y); batch.end(); ... } ... } |
Complete example
Combining all of the above, the class looks like this:
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | /** * Frame-by-frame animation example with LibGDX: * * http://www.pixnbgames.com/blog/libgdx/frame-by-frame-animations-in-libgdx/ * * @author angel */ public class GdxAnimationExample extends ApplicationAdapter { // Time while each frame keeps on screen private static float FRAME_DURATION = .05f; // To draw on screen private SpriteBatch batch; // Atlas with the definition of the frames "charset.atlas" private TextureAtlas charset; // Frame that must be rendered at each time private TextureRegion currentFrame; // Running animation private Animation runningAnimation; // Elapsed time private float elapsed_time = 0f; // Auxiliar variables to know where to draw the picture to center it on the screen private float origin_x, origin_y; @Override public void create () { batch = new SpriteBatch(); // Frames loading from "charset.atlas" charset = new TextureAtlas( Gdx.files.internal("charset.atlas") ); // Frames that compose the animation "running" Array<atlasregion> runningFrames = charset.findRegions("running"); // Building the animatino runningAnimation = new Animation(FRAME_DURATION, runningFrames, PlayMode.LOOP); // Calculates the x and y position to center the image TextureRegion firstTexture = runningFrames.first(); origin_x = (Gdx.graphics.getWidth() - firstTexture.getRegionWidth()) / 2; origin_y = (Gdx.graphics.getHeight() - firstTexture.getRegionHeight()) / 2; } @Override public void render () { // Clear the screen Gdx.gl.glClearColor(1.0f, .8f, .667f, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // Elapsed time elapsed_time += Gdx.graphics.getDeltaTime(); // Getting the frame which must be rendered currentFrame = runningAnimation.getKeyFrame(elapsed_time); // Drawing the frame batch.begin(); batch.draw(currentFrame, origin_x, origin_y); batch.end(); } @Override public void dispose() { // Resource releasing charset.dispose(); super.dispose(); } } </atlasregion> |
Source code
You can get the sample project from my GitHub repository.
Regards,

Thank you. Very concise and clear 🙂