How to create sprite sheets & animations for libGDX

In this tutorial you will learn how to use sprite sheets with libGDX.
Why using sprite sheets?
- By loading all graphics at once instead of numerous single images, the loading time of your app can be significantly reduced.
- Using a sprite atlas also enhances the game's performance, because textures only need to be set on the graphics device once, resulting in improved frame rates.
Creating a sprite sheet
The easiest way to create a sprite sheet is using TexturePacker — available for Windows, macOS and Linux:
Creating a sprite sheet with TexturePacker is quite simple:
- Drag and drop all the files you want to add to the left pane of TexturePacker
- Select the LibGDX framework and set the file path for the generated Data file. The Texture file can be left empty; TexturePacker will automatically save the PNG containing the sprite sheet next to the data file.
- Click on Publish sprite sheet

We recommend storing the individual sprites in a root folder named raw-assets, while only placing the sprite sheet data and texture file in the assets folder. This makes it easier to determine which assets must be deployed later.
Using a sprite sheet
Let's start with a new, empty project as you can generate it with the libGDX Project Setup Tool. The default implementation of the main class in the core module loads a sprite called badlogic.jpg and displays it on a red background.
In the previous section, we've already added the badlogic.jpg sprite to the sprite sheet. Now, we can load the sprite sheet and extract the sprite from it:
package com.mygdx.game;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.ScreenUtils;
public class MyGdxGame extends ApplicationAdapter {
SpriteBatch batch;
TextureAtlas textureAtlas;
Sprite sprite;
// highlight-end
@Override
public void create () {
batch = new SpriteBatch();
textureAtlas = new TextureAtlas("spritesheet.txt");
sprite = textureAtlas.createSprite("badlogic");
}
@Override
public void render () {
ScreenUtils.clear(0.57f, 0.77f, 0.85f, 1);
batch.begin();
sprite.setPosition(10, 10);
sprite.draw(batch);
batch.end();
}
@Override
public void dispose () {
batch.dispose();
textureAtlas.dispose();
}
}
We've also changed the background to a less annoying color:

Creating an animation
Now, we want to replace the static sprite with an animation. TexturePacker can automatically detect animation sprites: If the sprite filenames only differ by a sequence number suffix, TexturePacker will remove this suffix and export all the sprites as animation frames in the data file.
This makes it very easy to create an animation from a sprite sheet:
package com.mygdx.game;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.ScreenUtils;
public class MyGdxGame extends ApplicationAdapter {
SpriteBatch batch;
TextureAtlas textureAtlas;
Animation<Sprite> animation;
float stateTime = 0;
@Override
public void create () {
batch = new SpriteBatch();
textureAtlas = new TextureAtlas("spritesheet.txt");
animation = new Animation<>(0.066f, textureAtlas.createSprites("capguy"), Animation.PlayMode.LOOP);
}
@Override
public void render () {
ScreenUtils.clear(0.57f, 0.77f, 0.85f, 1);
stateTime += Gdx.graphics.getDeltaTime();
Sprite sprite = animation.getKeyFrame(stateTime, true);
sprite.setX(stateTime * 250 % (Gdx.graphics.getWidth() + 400) - 200);
batch.begin();
sprite.draw(batch);
batch.end();
}
@Override
public void dispose () {
batch.dispose();
textureAtlas.dispose();
}
}
The Animation
object acts as a container for animation frames. You can retrieve the frame to display at
a specific point in time using the getKeyFrame
method. Note that you need to track the elapsed time externally.
The complete example project is available on GitHub