Who is this tutorial for?
This tutorial is for anyone who wants to use the Flame Engine with sprite sheets. It'll cover the basics of adding sprites and animations to a scene, as well as some tricks like packing sprite sheets, and speeding up the 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 on your own blog or tutorial, or use them in your own 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 already, 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 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 sets up 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, you'll use TexturePacker, a powerful desktop application for creating sprite sheets and optimizing images for game development.
Please download TexturePacker from here:
After the installation click 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 you add a folder 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 available with 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 which is almost identical but now is only 110 KB — a 75% reduction in file size!
Loading the sprite sheet in your game
You just need to load the sprite sheet 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 easy. 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 give you a list of all frames.
This works with files named 01.png, 02.png, etc., but also with files ending with a
_ or - and a number. E.g. capguy/walk_01.png, capguy/walk_02.png, etc. will be detected as animation.
The animation name is the same as the sprite name but without the numbers.
In our case: capguy/walk.
To enable this animation detection feature, simply 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
create 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));Now go back into your simulator and reload the scene. You should now see your 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;
}
}Reloading the application should now show the character walking across the screen and wrapping around when he reaches the edge.
