How to use a Sprite Sheet Flutter Component with Flame 15 - Animated 2D Games

To generate an animated Sprite Sheet, we have to perform various operations that range from loading a sprite image to referencing it in the project; each state of the sprite has to have a defined size; 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);

An animation is nothing more than a sprite list, therefore, if you create a sprite list, you can use it in the corresponding Flame component to manage the animated sprites; for example:

class PlayeSpriteSheetComponent extends SpriteAnimationComponent {
  late double screenWidth, screenHeight, centerX, centerY;
  final double spriteWidth = 512.0, spriteHeight = 512.0;

  late double spriteSheetWidth = 680.0, spriteSheetHeight = 472.0;

  late SpriteAnimation dinoAnimation;

  @override
  Future<void> onLoad() async {
    super.onLoad();
    screenWidth = MediaQueryData.fromWindow(window).size.width;
    screenHeight = MediaQueryData.fromWindow(window).size.height;

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

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

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

    //sprite = spriteSheet.getSprite(1, 1);
    position = Vector2(centerX, centerY);
    size = Vector2(spriteSheetWidth, spriteSheetHeight);
    //sprite = await Sprite.load('Sprite.png');

    animation = [spriteSheet.getSprite(1, 1),spriteSheet.getSprite(1, 2)];
  }
}

Sprite animation with Sprite Animation Component

In Flame, we have a component to generate the animations based on a Sprite Sheet like:

In Flame's course and book to create 2D games, we created a function, with which, we can easily generate an animated list ready to use in a SpriteAnimation; we simply see the sprite sheet as an array and define the start and end position, as well as the size of the sprite sheet; among other options:

 

extension CreateAnimationByLimit on SpriteSheet {
  SpriteAnimation createAnimationByLimit({
    required int xInit,
    required int yInit,
    required int step,
    required int sizeX,
    required double stepTime,
    bool loop = true,
  }) {
    final List<Sprite> spriteList = [];


    int x = xInit;
    int y = yInit - 1;


    for (var i = 0; i < step; i++) {
      if (y >= sizeX) {
        y = 0;
        x++;
      } else {
        y++;
      }


      spriteList.add(getSprite(x, y));
      // print(x.toString() + ' ' + y.toString());
    }


    return SpriteAnimation.spriteList(spriteList,
        stepTime: stepTime, loop: loop);
  }
}

SpriteAnimationComponent: Tests

For this function, we will need the following parameters:

  1. Initial step at X (for example (3,0)).
  2. Initial step at Y (for example (3,0)).
  3. Number of steps (for example, the value of 6 corresponds to what we want 6 sprites).
  4. The width of the array (in the dino.png image the sprite matrix would be 3x3 so the width would be 3).
  5. Animation speed.
  6. If it is to be executed in a loop.

With this in mind, we'll create the following extension function that extends the SpriteSheet class:

lib/components/player_sprite_sheet_component.dart

 

extension CreateAnimationByLimit on SpriteSheet {
  SpriteAnimation createAnimationByLimit({
    required int xInit,
    required int yInit,
    required int step,
    required int sizeX,
    required double stepTime,
    bool loop = true,
  }) {
    final List<Sprite> spriteList = [];

    int x = xInit;
    int y = yInit - 1;

    for (var i = 0; i < step; i++) {
      if (y >= sizeX) {
        y = 0;
        x++;
      } else {
        y++;
      }

      spriteList.add(getSprite(x, y));
     // print(x.toString() + ' ' + y.toString());
    }

    return SpriteAnimation.spriteList(spriteList,
        stepTime: stepTime, loop: loop);
  }
}

The most important thing is to note the for block in which we traverse the sprite array just as in the examples explained above; with this sprite list, we generate the animation using SpriteAnimation.spriteList().

With the previous code defined in the PlayeSpriteSheetComponent class, we define the animation property, using the function called createAnimationByLimit() that we created previously, the rest of the properties are the same used in any other SpriteComponent or PositionComponent type component that we presented in previous examples; properties like size, position are needed to indicate the size and position of the sprite.

Remember that this material is part of my complete course on Flame Flutter and book on developing 2D games with Flame.

Video Transcript

Once we have created this function that we created previously we are going to test it to see how it goes here In the load function we are going to use it Obviously we cannot use the Sprite since we are using a Sprite Animation component here Remember to make this change so that you can use here now the Animation property is the place the Animation is the equivalent now Dale Pride only that this is animated an animated component according to what we want here that is being the only difference and for this reason we have to pass here our spray Animation which is the function that we want here and it is what is returning here exactly this in a very simple way instead of doing all this logic for each animation And we have the help function well having said that here we are going to call our function we indicate here Sprite sheet point Remember that this is why it was that we attended to this kind of spray sheet over here we have that extension right here in this file we are going to place our function called create Animation by limited that receives this bunch of things that well you should not have doubts at this point that what we are going to pass here by the way A good little detail Sorry that they already correct it here you can indicate it true by default so that we remove Here this work already with this you can remove here for example the mourning one that would not be necessary okay we already made the first correction in short we are going to indicate the initial limit lets put it very simple For now Then we do more tests obviously 00 so here we put 00 it is always good to put edge cases to see how it behaves here the number of steps that we want well obviously we want all of them but we are going to indicate that we want I dont know the first six we put 5 since well lets see how it goes but it would start at zero and well we would have to put 6 since when they are the same this condition is already met it will not continue to execute ok here we put it now we are going to put the size we are working with this one which is the one we have here called dino we can look for it here we have it at these steps it would be 012 it would be the size of two so here we put two since finally the speed I am going to put for example to do the first tests point 5 so that it goes slow and Well there we can see more clearly and this would be all we save to load everything We already have it lets open our image here since this is the one we are enlarging I am going to open it here I am going to take it here And it is that we have it clear it goes very slow But remember that here you can speed it up for example put a zero here ahead we reload everything and now we have it here its running pretty fast Im going to put it here at point 8 there its going much better we can also see the prints here to see if its doing what we want look it starts at zero zero Remember that we passed 6 were going to count and here we have six that is to say in the return steps its working correctly since again we want 6 here its returning Step zero zero which is exactly what we want 00 then we go to zero one zero two well in this case we can now bring this other image that although its not the same we can take it here as a reference it would be 001 and 02 right here as you can see then we want since we got here to the maximum quota according to the size defined here the 6 in X in 2 we go with the next step which would be 10 here we change it would be the x1011 and 12 Exactly the same as the values that we have here in this case it doesnt happen anymore the next one because we want it is only six steps if here we put 7 we save we reload and place our image here again Here we are going to return or we are going to go to the next step which would be right here and there we had it up to 2 then the algorithm seems to be working correctly And remember Well here was the importance here of placing this in the negation and here remember to place the 1 here.

    final List<Sprite> spriteList = [];

    int x = xInit;
    int y = yInit - 1;

    for (var i = 0; i < step; i++) {
      if (y >= sizeX) {
        y = 0;
        x++;
      } else {
        y++;
      }

So that the first check that we do here I also deleted it because there we validate the other way but thats how I did it so at this point we can place the rest of the steps Remember that we are starting here at 00 this would be lets see 0 and 1 in and two in and to place the rest of the steps it is very simple this would be the step the step zero zero one two three four five six seven would be seven steps that is to say here we place the function we place it here we already have it up to seven right there we already have the corresponding animation as you can see it works correctly we do not have any error and with this we create a fairly reusable function as I indicated here at this point that we created it we can also talk a little about that You can create the function with the structure you want Of course I consider it to be quite malleable that is you can adapt it quite well just as we saw indicating from which step you want and how many steps you want etc But you can also create a function that works by rows which I brought by columns etc It all depends on how you want to organize yourself.

Remember that this material is part of my complete course on Flame Flutter and book on 2D game development with Flame.

- 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 2d 00:38!


Udemy

!Courses from!

4$

In Academy

View courses

!Books from!

1$

See the books
¡Become an affiliate on Gumroad!