Gfx Engine - Animated Sprites and Sprite Atlases
In the previous example, we got acquainted with how texture atlases are created and used. We created a couple of sprites with simple animation and rendered a landscape from graphic tiles. But is this the only area of application for texture atlases?
Not quite.
Previously, we did implement sprite animation using a custom FireSpriteAtlasElement class inherited from Cubios::Gfx::SpriteAtlasElement. However, this method is not very convenient and is more suitable for cases where you really need to have deep control over the playback of an animation sequence.
As we know, GFX Engine has a separate class for creating animated sprites - AnimatedSprite. Since SDK 6.3, this class provides the ability to use texture atlases to load animation frames!
What is this for? Why is it more convenient than having each frame of animation in a separate file?
Well, there are several reasons:
-
Reduced Memory Usage: Texture atlases pack frames together efficiently, reducing unused space (padding) that might exist in separate image files. This leads to a smaller memory footprint.
-
Fewer Files: With a single file for multiple frames, there’s less memory overhead for file headers and metadata.
-
Faster Loading: Loading a single texture atlas file is faster than loading multiple individual image files, as it minimizes file I/O operations.
-
Simpler Management: Animating from a texture atlas is often easier because all frames are organized in one file, and the coordinates can be precomputed or handled by the GFX Engine.
-
Consistency: rames are guaranteed to have the same texture properties, like filtering and mipmap settings, since they share the same texture.
So by using a texture atlas for your animations, you streamline asset management, improve runtime performance, and reduce the complexity of animation workflows. It’s a best practice in game development, especially for resource-constrained environments.
The process of creating an animated sprite using a texture atlas is not much different from creating a sprite in any other way:
- First, the
SpriteAtlasitself is created, into which a picture with animation frames is loaded - Next, an
AnimatedSpriteis created, initialized with a texture atlas and registered in the scene
then
- The sprite object gets added to the screen inside the
Begin()-End()block in theon_Render()function - And gets disposed when it's not used anymore to free system resources
Let's look at each step separately.
Step 1 - Initialization
The SpriteAtlas class has just one constructor:
As you can see, to create a sprite atlas you only need two things - the name of the texture file containing the sprite images and a pointer to the Scene object:
-
std::string name
Name of the texture file -
Cubios::Scene scene
Pointer to Scene object
Once the SpriteAtlas instance has been created, elements (sprites) need to be added.
The AddSprite method is used for this:
Just like when creating a regular sprite, the first parameter of the atlas sprite element is a unique identifier that allows you to find this sprite in the scene. The second parameter is an object of the Math::Reсt2 class, describing the integer coordinates and size of the sprite image on the texture atlas in pixels.
-
uint32_t id
Sprite resource identifier -
Cubios::Math::Rect2 rc
Sprite texture rectangle
The AnimatedSprite class has several constructors that take a SpriteAtlas as a parameter:
To create an instance of the class, you simply need to pass a pointer to the texture atlas that was created earlier.
Step 2 - Rendering
The way the AnimatedSprite object is rendered is absolutely no different from how regular sprites are rendered. Sprites are added to the scene inside the Begin-End block.
The only additional action is calling the int16_t Tick(uint32_t dt) function in the on_Tick() callback.
This is necessary in order to "inform" the animated sprite the current time so that it can correctly play the animation.
The Example
So, the example...
On the one hand, we could just take any animation as an example and put it on the screen, right? Yes, but that's not interesting!
Let's make something better, like a short cartoon where a boy walks under the moon?
The first step, as always, is the initialization of resources in the InitializeResources() function:
As you can see, we create two texture atlases - with animation of a walking boy animation.png and a rotating moon earth.png (sorry, the Earth - we couldn't find a ready-made animation of a rotating moon in the public domain). Next, four objects are created - a background, 2 animated sprites and a simple sprite for the foreground.
And the rest is very simple - we pass time to animated sprites in on_Tick() callback
and render them in on_Render()
and finally, we render our background and flying fireballs in on_Render()
Just a little bit of coding - and we get our cartoon on WOWCube!