How to use a Sprite Sheet in Flutter with Flame 13 - Animated 2D Games

A sprite is nothing more than an object or character and they are widely used in any game engine such as Unity; in video game development, sprites are where all the movements (states) of a character or object are included; therefore, it is common for a 2D game to have multiple images for each animable object.

we are interested in not only processing a single image, but several of them, for this, we will use an image that consists of several images, like the one generated previously.

A sprite sheet is an image that contains several sprites or smaller images used in 2D game development. Sheets sprites typically represent objects, characters, and game items, and can be static or animated. The sprite sheet allows the game to load multiple images required for the game at once, which can improve loading efficiency and overall game performance. By having all the images in a single image, it makes it easier to manage and organize graphic resources in 2D game development.

Case study

Finally, at the level of our code, we will create the following class:

lib/components/player_sprite_sheet_component.dart

import 'package:flame/sprite.dart';
import 'package:flutter/material.dart';

import 'package:flame/flame.dart';
import 'package:flame/components.dart';

import 'dart:ui';


class PlayerSpriteSheetComponent extends SpriteComponent {
  late double screenWidth, screenHeight, centerX, centerY;
  final double spriteSheetWidth = 680, spriteSheetHeight = 472;

  @override
  Future<void>? onLoad() async {
    //sprite = await Sprite.load('tiger.png');

    final spriteImage = await Flame.images.load('dino.png');
    final spriteSheet = SpriteSheet(image: spriteImage, srcSize: Vector2(spriteSheetWidth, spriteSheetHeight));

    sprite = spriteSheet.getSprite(2, 1);

    screenWidth = MediaQueryData.fromWindow(window).size.width;
    screenHeight = MediaQueryData.fromWindow(window).size.height;

    size = Vector2(spriteSheetWidth, spriteSheetHeight);

    centerX = (screenWidth / 2) - (spriteSheetWidth / 2);
    centerY = (screenHeight / 2) - (spriteSheetHeight / 2);

    position = Vector2(centerX, centerY);

    return super.onLoad();
  } 
}

Explanation of the previous code

As you can see in the previous code, we define the size for each sprite in our sprite sheet; for the image we select, it would be 680 pixels x 472 pixels:

To do this, we use a couple of properties:

late double spriteSheetWidth = 680.0, spriteSheetHeight = 472.0;

It is important to note that you must specify the size according to the sprite you are using.

We load the sprite sheet:

var spriteImages = await Flame.images.load('dino.png');

And we define the spriteSheet so that it can be manipulated through a property; It is in this step that we use the individual dimensions of each state:

final spriteSheet = SpriteSheet(image: spriteImages, srcSize: Vector2(spriteSheetWidth, spriteSheetHeight));

Finally, it is now possible to consult each position of one of the steps of the sprite sheet individually:

sprite = spriteSheet.getSprite(1, 1);

There are sprite sheets with different sizes for each frame or sprite, therefore, you must be sure that the sprite sheet you are using has the same sizes for each of the sprites, in this example it is 680x472 px.

Load a sprite

It is also possible to load sprite using the load function; use the function loadSprite from the Flame class to load the sprite: sprite = await Flame.images.load('image.png');

Once the sprite is loaded, you could use the SpriteComponent component to render it in-game as if it were a component; this may not seem like much, but when using Flame components, we can use features like the collision system, data entry, and in general, any functionality available in a PositionComponent class.

Here is an example of how to load a sprite in Flame:

import 'package:flame/components/sprite_component.dart';
import 'package:flame/flame.dart';
class MyGame extends BaseGame {
 SpriteComponent _spriteComponent;
 MyGame() {
   _loadSprite();
 }
 void _loadSprite() async {
   var image = await Flame.images.load('ruta/a/la/imagen.png');
   _spriteComponent = SpriteComponent.fromImage(0, 0, image);
   add(_spriteComponent);
 }
}

This code will create a new game (MyGame) and load a sprite using Flame's load function, and render it to the SpriteComponent.

Remember that this material is part of my course and book on Flame for 2D game creation.

Video Transcript

The next operation that we are going to do would be to load our sprites to start working with it so for this we are going to generate a new component here I recommend that you copy and paste this one because it is going to be practically the same so we copy it paste it I am going to rename it Here I am going to place these half crazy names that I placed since now it is a spray shift here I am going to place Player Sprite sheet component point dart This is the big name it tells it that I am going to give it here I place it I place the correct references and perfect and here we have it OK Good and here it is going to simplify it a little for example removing the keyboard I am not interested So we remove the mixing go down to the Kevin section and delete everything I am not very interested either so we can remove it at least for now and we can now clean up the imports a little Here we also go through the imports a little Ok lets start making changes here logically we are not going to load this like this because we are going to load now one step at a time of ours We will see it but we can comment on it here so that it does not make noise for the rest here the position all this the vector at some point load the spray compose or a component of that Remember that we are going to work with is the image that we have here with component I mean these images we are going to load a promise and then we can vary it and later in the future we animate it but little by little for now it is to load it Honestly we are going to need to do the following Ok up here We are going to load our image for that we have to do since now it is a Sprite the thing changes a little bit we are going to create a variable called Sprite image this can have any name but well in which I am going to give it and over here we make a flame point and point and we indicate here the name that is Dino point png we are going to load this the package we have it here in flame So for this we are going to create

var spriteImages = await Flame.images.load('dino.png');

Placing var Sprite sheet will be equal to Sprite and here we have to reference several things among them we have to reference the image as you can see image will be the sprite Sheet that we defined here This goes down here sorry it is for image over here it does not give an error if we analyze it here we are placing Future since again any operation is Future here we forgot to put White and here it takes it without any problem Ok over here it is

final spriteSheet = SpriteSheet(image: spriteImages, srcSize: Vector2(spriteSheetWidth, spriteSheetHeight));

The size the size that you might be asking yourself in this case logically is not of the document that is of the document as a whole that is of all of this but of each one of the sprite sheets that I think we showed before but I also have the table here and now the dimensions that appear here When you read the properties Remember that each one of these sheets have exactly the same size and this is due to the animations the space they occupy which would be more or less around here as you could see individually anyway the dimensions are 680 by 472 here you have to obviously place the ones you are using for your spritetest in case you are expanding a different one here to the one in the course so here to keep this simpler we are going to create a couple more properties here I am going to place final I am going to call it as Sprite that is going to be equal to in this case to the one of 680 which is the width I put 680 comma lets go with the other Sprite shift of th that is going to be equal to And if we look for it it will be equal here to the one in the course 472 472 we place the semicolon and now here we reference it for this here we use again a twodimensional vector which is what it tells us here it requires a twodimensional vector and we indicate here our Sprite with it is already a tongue twister and Sprite we place the semicolon and with this we already load our Sprite Here I am going to place it Well okay there we have it now what do we do

final spriteSheet = SpriteSheet(image: spriteImages, srcSize: Vector2(spriteSheetWidth, spriteSheetHeight));

With this we can finally load our Sprite since in the end Remember that Depending on the component you want to use you always have some properties that you have to define some are mandatory others are more optional but in this case the Sprite would be mandatory in which we have here that we have not defined yet By the way all this is going to be placed final Now yes So here I am going to indicate that my Sprite is going to be equal to something that is used in the spray sheet point we indicate here the function called get Sprite here we have it which tells us a column since if you look here what we have is a matrix 001 02 and so we are going to talk about this but it is what it is asking us we are going to place the simple thing we place 00 we place a semicolon we save and we are going to reload to see what we have Ah sure I always forget here we use the new component here we have it which would be Player Spice we save We already have it well it appears distorted here But at least we have it now we are going to see that but here you can place another for example one I was going to place a little more so that it changes for example three

sprite = spriteSheet.getSprite(1, 1);

I reload everything and look that now here it appears in another state OK Lets check here to see if it appears distorted or is it me but it appears here that it appears a little like squashed it already seems squashed Ah sure it makes all the logic in the world since now the dimensions change thats why it seems squashed Im going to remove this because its no longer necessary and we place the new ones here just like here Now yes we save we reload We already have it Now our Sprite looks correct Ok how does this joke work What values do we have to place here for that here I prepared an image I have it here in downloads I have it I think its this one here is the image These are the positions that we could use for this Sprite that we defined Notice that there could be two here perfectly you could use it to load other resources for another animation you can also tell them a little smaller etc you can do many things there but for the tests that we are doing this was left dead here that would obviously be inefficient since again two images would enter here anyway getting back to the subject you can place these values that depends Well you can handle it as if it were again a matrix 001 0210 that is to say because we are on the Y axis 00 here we already grow by one on the Y axis and here by two and up to here we arrive Because also positions Then if we go here in this row and here we are in the position well on the x axis and it would be the same one two and three until we get here we already have it If you want to see this a little more in practice you can place the edge here which would be 3 0 we save it there we have it I am going to place this image I think for here so that it looks better there you have it and well it is not this surcharge since I have in the and it should be seen that I placed here 30 although this image is different Now that I am seeing it it is different now that it is another state that I placed here Well yes I am more it is slightly different since it will be from another resource I thought that I had stayed the same but now that I am seeing here I grab outside of walking but in essence it is the same in the same way we could even try this in this case I made the sprise for the walking part you can already do it too and try it here in the course well in the project in this case the one of 30 gives us zero it gives us nothing because if we look here we have a 0 1 and 2 we get up to two then here the same thing applies we leave a dead space here But anyway going back to this here it would be zero it would be one it would be two then And this would be in and it would be 2 1 so this is the most that we can place we put two 1 we save We already have it What happens if we put 22 Well the same thing that happened right now it no longer exists it went out of the Range so here we are not going to see anything we reload everything We already have it but well as I tell you this is how it works even if it is a different image well understand why it is the same principle of a matrix It is simply a matrix a root in any programming language is what we have here and in this way we can access the images independently here the key the most important thing apart from that it changes a little the way of loading the resource that now is this way and not like this here define the Sprite with the corresponding dimensions for our image the image individually that was the one I showed you here is not the image as such of the Sprite but an image of each of the states that we have for example this one we can get the size for the rest that would be 680 by 472 which is what we have here since if other dimensions are placed Now here the thing is going to be distorted for example here I put 512 Im going to save we reload look now only a fragment will appear and the same if we place for example one and one it will not be displayed correctly there as you can see even in some points you will see that they are cut or another image appears but well I think that with this its operation is clear for the rest of the much more to say of course the next thing we have to do would be to animate all this but we will see that later

- Andrés Cruz

En español

Andrés Cruz

Develop with Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz In Udemy

I agree to receive announcements of interest about this Blog.

!Courses from!

10$

On Udemy

There are 1d 04:56!

Udemy

!Courses from!

4$

In Academy

View courses

!Books from!

1$

See the books
¡Become an affiliate on Gumroad!