We delve into the exciting realm of 2.5D game development using Flutter’s Flame engine. From understanding sprite stacking techniques to creating your own stacked sprite models, this article provides an insightful journey into enhancing your Flame game development skills.
Table of Contents
2.5D with Flame
Those of you who have used the Flutter-based Flame game engine to build a game or have looked into it would already know that, like Flutter itself, Flame is limited to 2D. So while true 3D is not supported, all is not lost as you can still get a 3D-like, “2.5D” experience for your game idea by using a technique called “Sprite Stacking”. For those that may be new to Flame game development, you can get up to speed with the basics from a previous article.
Stack’em High!
So what is “Sprite Stacking”? It’s a technique to give you a pseudo 3D effect by taking advantage of the fact that if you draw an object as a set of 2D layers or “slices” stacked on top of each other, with a single-pixel vertical offset, you will get the visual appearance of a “3D-ish” object, hence the name of sprite stacking.
As they say, a picture is worth a thousand words, so the animation below showing how a simple tree object can be made to have a 3D appearance, when made up of a series of 2D “slices”, should help illustrate the concept more clearly:
Using Stacked Sprites in Flame
Now that we know how stacked sprites work in general, how can we make use of them in our Flame games? First off, we need a stacked sprite asset! To start with, I headed over to Itch.io, where I found the excellent sprite pack. While the pack is free, please consider making a donation to the creator, as I did, to thank them for making these cool sprites freely available!
Now that we have some assets to work with, let’s have a look at one of the car images (enlarged significantly):
Looking at this image (in games called a “sprite sheet”), we can see that it’s been split up into 9 separate “cells” or sub-images, each making up a vertical “slice” of the car. Given this asset, what we need to do is, as per the technique I outlined above, to read in each of those sections of the image and then draw each of the slices, one on top of the other, but offsetting each slice by 1 pixel in the vertical direction.
Join Our Whatsapp Group
Join Telegram group
The code required for this task can be simplified using Flame’s SpriteBatch
class:
Future<void> getBatch(String name) async {
late SpriteBatch _batch;
final sheetImg = await game.images.load('$name.png');
_batch = await SpriteBatch.load('$name.png');
const double spriteWidth = 16; //hardcode width of sprite sheet cells
const double spriteHeight = 16; //hardcode height of sprite sheet cells
final sliceCount = sheetImg.width ~/ spriteWidth;
for (int i = 0; i < sliceCount; i++) {
_batch.add(
source: Rect.fromLTWH(spriteWidth * i, 0, spriteWidth, spriteHeight),
offset: Vector2(0, -i.toDouble()),
anchor: Vector2.all(spriteWidth / 2),
rotation: 0,
);
}
}
Apart from loading the image and setting the size (in pixels) of the image slices, the main action happens in the for loop, where we add each slice to the SpriteBatch
applying an offset of 1 pixel of y per slice and setting the anchor to be in the middle of each slice. It also allows us to specify the rotation property, which we’ll make use of in a moment.
Now, let’s integrate this code into a Flame game:
class FlamingSprites extends FlameGame with HasDraggableComponents {
late final StackedSpriteComponent _carOne;
@override
Color backgroundColor() => Colors.blueGrey;
@override
FutureOr<void> onLoad() async {
await super.onLoad();
_carOne = StackedPreview(this, "BlueCar", false)..scale = Vector2.all(9);
_carOne.position = Vector2.all(300);
add(_carOne);
}
}
This code sets up a Flame game with a draggable component (HasDraggableComponents
) and loads a stacked sprite component named BlueCar
. The sprite is then positioned and added to the game. When running the game, we should see something like this:
Adding Rotation to the Stacked Sprites
If we now pass in a value instead of just 0 for the rotation (and make it in radians):
rotation: _stackAngle * radians2Degrees,
We update this rotation value as time passes in our game’s update
method:
@override
void update(double dt) {
super.update(dt);
angle += 0.0005; //spin car around slowly
}
With these changes, we get:
Adding Rotation to the Stacked Sprites
If we now pass in a value instead of just 0 for the rotation (and make it in radians):
rotation: _stackAngle * radians2Degrees,
We update this rotation value as time passes in our game’s update
method:
@override
void update(double dt) {
super.update(dt);
angle += 0.0005; //spin car around slowly
}
With these changes, we get:
Creating Stacked Sprite Models
While we’ve covered the coding aspects of using a stacked sprite in our Flame games, we’ve so far just used pre-made sprites. But what if you’re keen to make your own? While you could try making the sprite sheets “by hand” using a sprite editor like Aseprite, a much easier way is to use the excellent open-source tool Goxel, which has downloadable versions for Linux, Android, Windows, MacOS, iOS, as well as a web-based version! 🎉🎉 Goxel lets you design your 3D models in a much easier fashion and then quickly export them to the required sprite sheet PNGs.
Note: If you are using a HiDPI monitor or laptop screen (as I was on Ubuntu 22.04), you will likely want to get the HiDPI branch, which has fixes for UI scaling issues. These fixes should then be available in a future 0.11.1 version of Goxel when it’s released.
Another good free, but not open-source, voxel editor I came across is Magica Voxel. Using it is described in this tutorial and it can also be downloaded.
Join Our Whatsapp Group
Join Telegram group
If you do go down the path of making your own sprite sheets with Magica Voxel instead, one thing you will quickly discover is that when it exports to a PNG sprite sheet, it does so as a vertical, not horizontal, array of slices and it puts the bottom-most slice at the bottom of the sheet. This, of course, won’t work with the code I showed above, but it’s not too difficult to modify it to work with sprite sheets in this format. The code required for this modification is:
final sliceCount = sheetImg.height ~/ spriteHeight;
for (int i = 0; i < sliceCount; i++) {
_batch.add(
source: Rect.fromLTWH(0, spriteHeight * (sliceCount - i), spriteWidth, spriteHeight),
offset: Vector2(0, -i.toDouble()),
anchor: Vector2.all(spriteHeight / 2),
rotation: _stackAngle * radians2Degrees,
);
}
Use the source $first_name
…
If you want to see a full working example (with a more polished version) of the code for this article, you can find it in the accompanying source code repository.
Learning More
To learn about the basic principles involved in using sprite stacking, I can recommend this video from [YouTuber’s Name], whose idea on illustrating sprite stacking by drawing a basic tree in a drawing app I shamelessly reused for my animated diagram above.
But Wait, There’s More!
While we’ve looked at how to make use of individual stacked sprites, this technique would usually be used for multiple if not all visual elements in a game world. The approach I’ve shown here using Flame’s SpriteBatch won’t work for multiple stacked sprites if we want to make sure that Z-ordering is handled correctly. Luckily, @Wolfenrain has already done that hard work for us with his cool Flame game engine extension, which can handle whole game sprite stacking.
FAQs
What is Sprite Stacking and how does it relate to Flame?
Sprite Stacking is a technique used to create a pseudo 3D effect by layering 2D sprites on top of each other with slight vertical offsets. In the context of Flame, a Flutter-based game engine, Sprite Stacking allows developers to achieve a 2.5D visual style within their games, despite Flame being limited to 2D rendering.
Join Our Whatsapp Group
Join Telegram group
How can I use Stacked Sprites in my Flame games?
To use Stacked Sprites in Flame, you first need a stacked sprite asset. You can obtain these assets from various sources, such as Itch.io, or create your own using tools like Goxel or Magica Voxel. Once you have the assets, you can integrate them into your Flame game using the SpriteBatch class to handle the rendering of the stacked sprites.
How do I add rotation to Stacked Sprites in Flame?
To add rotation to Stacked Sprites in Flame, you can modify the rotation property of each sprite within the SpriteBatch. By updating the rotation value over time in the game’s update method, you can achieve dynamic rotation effects for your stacked sprites.
How can I create my own Stacked Sprite models?
Creating your own Stacked Sprite models involves designing 3D models and exporting them to sprite sheet PNGs using voxel editing software like Goxel or Magica Voxel. Once you have your sprite sheet, you can follow the same process as using pre-made sprites to integrate them into your Flame game.
Join Our Whatsapp Group
Join Telegram group
Where can I find more resources to learn about Sprite Stacking and Flame game development?
You can find more resources to learn about Sprite Stacking and Flame game development through tutorials, videos, and community forums. Additionally, exploring the source code of existing Flame projects and experimenting with different techniques will help you deepen your understanding and improve your skills.