Who is this tutorial for?
This tutorial is for anyone interested in using Flame Engine with sprite sheets. It covers the basics of adding sprites and animations to a scene, as well as techniques like packing sprite sheets, and optimizing loading times.
This is the scene you are going to create in this tutorial:
Creating a simple Flame game scene
Downloading the assets
Download the sprites and background image from here: assets.zip. You can use these assets for learning purposes. Please don't publish them in your own blog or tutorial, or use them in a game or app without my written consent.
Extract the contents into a folder called assets inside your Flutter project.
The archive contains the graphics you see in the demo above:
- background.png
- capguy
- turn_01.png ... turn_06.png
- walk_01.png ... walk_08.png
We also offer you the full source code for this tutorial on GitHub.
Installing Flame
If you haven't created a project yet, start by setting up a new Flutter project:
flutter create my_game
cd my_gameNow, add flame and flame_texturepacker to your project:
flutter pub add flame flame_texturepackerThis command automatically adds the dependencies to pubspec.yaml and runs flutter pub get.
Next, you need to configure the assets. Open your pubspec.yaml file and add the following assets section to the flutter configuration.
Make sure to keep the indentation correct and don't forget the trailing slash:
flutter:
assets:
- assets/images/sprites/
- assets/images/spritesheets/Getting started with a simple scene
Start by creating a lib/main.dart file with this content:
import 'package:flame/game.dart';
import 'package:flame/components.dart';
import 'package:flutter/material.dart';
void main() {
runApp(GameWidget(game: MyGame()));
}
class MyGame extends FlameGame {
@override
Future<void> onLoad() async {
// load the background image
// Note: Flame's base directory when loading images is assets/images
final background = await loadSprite('sprites/background.png');
// add background as a component
add(SpriteComponent(sprite: background));
}
}This code initializes a basic Flame game and loads the background image.
Testing the scene
Run the application on your preferred device or simulator:
flutter runYou should see the background of the game scene:
Creating a sprite sheet
To create the sprite sheets, we use TexturePacker, a powerful desktop application for creating sprite sheets and optimizing images for game development.
Please download TexturePacker from here:
After installation, activate the trial by clicking on Try TexturePacker Pro.
In the main screen:
- Drop the sprites folder onto the left panel
- Choose data format Flame Engine on the top of the right panel
When a folder is added to TexturePacker, it collects all sprites in that folder recursively. The subfolder names are prepended to the sprite names. In our example, the sprites will be accessible using names like capguy/walk_01, capguy/walk_02, and so on.
The main folder name "sprites" is omitted by default. If you want to include it as part of the sprite name, use Prepend folder name from the Advanced settings.
Create a new folder called spritesheets in your project's assets/images directory. In TexturePacker, click on the folder icon next to Data file and navigate to the spritesheets folder. Name the data file cityscene.atlas.
Finally, press Publish sprite sheet to write the sprite sheet to your project folder.
This automatically creates 2 files:
- spritesheets/cityscene.png - the sprite sheet image
- spritesheets/cityscene.atlas - the sprite sheet data file
Optimizing your sprite sheets for faster loading
The resulting cityscene.png is about 450 KB in size. But we can do better! TexturePacker can dramatically reduce the file size of your sprite sheets, making your game load faster.
Simply change the Texture format from PNG-32 to PNG-8 (indexed) and press Publish sprite sheet again. The result is a sprite sheet that looks almost identical but is now only 110 KB — a 75% reduction in file size!
Loading the sprite sheet in your game
To use the sprite sheet in Flame, we need to load it using the flame_texturepacker package.
Import the package in your lib/main.dart:
import 'package:flame_texturepacker/flame_texturepacker.dart';Then, inside onLoad, load the sprite sheet:
// load the sprite sheet
final atlas = await atlasFromAssets('spritesheets/cityscene.atlas');Adding a sprite from a sprite sheet
Adding a sprite from the sprite sheet is simple. Let's fetch the background sprite from the sprite sheet instead of loading it directly:
// fetch the background sprite from the sprite sheet
final background = atlas.findSpriteByName('background');
// add background as a component
add(SpriteComponent(sprite: background));Adding and playing animations
TexturePacker can automatically detect animations in your sprites and create lists of all frames.
This works with files named 01.png, 02.png, etc., but also for files ending with a
_ or - followed by a number. For example, capguy/walk_01.png, capguy/walk_02.png, etc., will be detected as an animation.
The animation names are the same as the sprite names, but without the trailing numbers.
In our case: capguy/walk.
To enable this animation detection feature, go back to TexturePacker:
- Use the button on the bottom right to switch to the Advanced settings.
- Enable the Auto-detect animations checkbox
- Update the sprite sheet by pressing Publish sprite sheet.
Let's see how we can create an animated sprite in Flame. Add the following Player class to your code:
class Player extends SpriteAnimationComponent {
final TexturePackerAtlas atlas;
final double sceneWidth;
Player(this.atlas, this.sceneWidth) : super(position: Vector2(100, 400));
@override
Future<void> onLoad() async {
// create the walking animation
final walkSprites = atlas.findSpritesByName('capguy/walk');
animation = SpriteAnimation.spriteList(
walkSprites,
stepTime: 0.1,
loop: true,
);
}
}This class uses the findSpritesByName method to retrieve all sprites of the animation and creates a SpriteAnimation from them.
In MyGame.onLoad(), add an instance of the Player to your game:
// create and add the player
add(Player(atlas, background!.srcSize.x));Go back to your simulator and reload the scene. You should see the character walking in place.
To make the character move across the screen, update the Player class by adding an update method:
double speed = 100.0; // pixels per second
@override
void update(double dt) {
super.update(dt);
// move the player horizontally
position.x += speed * dt;
if (position.x >= sceneWidth) {
position.x = -size.x;
}
}Reload your application, and you should see the character walking across the screen and wrapping around when reaching the edge.
