Como utilizar un Sprite Sheet Componente Flutter con Flame 15 - Juegos 2D animados

Para generar un Sprite Sheet animado, tenemos que realizar varias operaciones que van, desde cargar una imagen sprite, hasta referenciarla en el proyecto; cada estado del sprite, tiene que tener un tamano definido; para ello, usamos un par de propiedades:

late double spriteSheetWidth = 680.0, spriteSheetHeight = 472.0;

Es importante notar que, debes de especificar el tamaño acorde al sprite que estés utilizando.

Cargamos el sprite sheet:

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

Y definimos el spriteSheet para que pueda ser manipulado mediante una propiedad; es en este paso que, utilizamos las dimensiones individuales de cada estado:

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

Finalmente, ya es posible consultar de manera individual cada posición de uno de los pasos del sprite sheet:

sprite = spriteSheet.getSprite(1, 1);

Una animacion, no es mas que una lista de Sprite, por lo tanto, si formas un sprite list, puedes utilizarlas en el componente correspondiente de Flame para manejar los sprite animados; por ejemplo:

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)];
  }
}

Animacione de sprite con SpriteAnimationComponent

En Flame, tenemos un componente para generar las animaciones en base a un Sprite Sheet como:

En el curso y libro de Flame para crear juegos en 2D, creamos una función, con la cual, podemos generar facilmente un listado animado listo para usar en un SpriteAnimation; simplemente vemos el sprite sheet como una matriz y definimos la posición inicial y final, ademas del tamaño del sprite sheet; entre otras opciones:

 

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: Pruebas

Para esta función, necesitaremos los siguientes parámetros:

  1. Paso inicial en X (por ejemplo (3,0)).
  2. Paso inicial en Y (por ejemplo (3,0)).
  3. Cantidad de pasos (por ejemplo el valor de 6 corresponde a qué queremos 6 sprites).
  4. El ancho de la matriz (en la imagen de dino.png la matriz de sprite sería de 3x3 por lo tanto, el ancho sería de 3).
  5. Velocidad de la animación.
  6. Si se va a ejecutar en bucle.

Teniendo esto en cuenta, crearemos la siguiente función de extensión que extienda a la clase SpriteSheet:

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);
  }
}

Lo más importante es notar el bloque del for en la cual, recorremos la matriz de los sprite justamente como en los ejemplos explicados anteriormente; con esta lista de sprite, generamos la animación utilizando SpriteAnimation.spriteList().

Con el codigo anterior definido en la clase PlayeSpriteSheetComponent  definimos la propiedad de animation, usando la función llamada createAnimationByLimit() que creamos anteriormente, el resto de propiedades, son las mismas empleadas en cualquier otro componente de tipo SpriteComponent o PositionComponent que presentamos en anteriores entregas; propiedades como size, position son necesarias para indicar el tamaño y posicion del sprite.

Transcripción del vídeo

Elaborada la función esta que creamos anteriormente vamos a probarla a ver qué tal nos va por aquí en la función del load vamos a utilizarla ya obviamente no podemos emplear el Sprite ya que estamos empleando aquí un componente de Sprite Animation component. Recuerda hacer este cambio para que puedas emplear aquí ahora la propiedad Animation es el lugar el Animation viene siendo el equivalente ahora Dale Pride solamente que esto es animado un componente animado según lo que queremos aquí esa viene siendo la única diferencia y por tal motivo tenemos que pasarle aquí nuestro spray Animation que es la función que queramos acá y es lo que está devolviendo aquí justamente esto de una manera muy sencilla en vez de hacer toda esta lógica para cada animación Y tenemos la función de ayuda bueno dicho esto por aquí vamos a llamar a nuestra función indicamos aquí Sprite sheet punto Recuerda que las viene siendo esta por eso es que fue que atendimos esta clase de spray sheet por aquí tenemos esa extensión justamente aquí en este archivo vamos a colocar nuestra función llamada create Animation by limited que recibe este montón de cosas que bueno no deberías de tener dudas en este punto que lo que vamos a pasarle aquí por cierto Un detallito bueno Disculpa que ya la corrijan aquí lo puedes indicar true por defecto para que nos quitemos Aquí esta labor ya con esto puedes quitar aquí por ejemplo el de luto que no sería necesario vale ya hicimos la primera corrección en fin vamos a indicar el límite inicial vamos a colocarlo muy sencillo De momento Luego hacemos más pruebas obviamente de 00 así que aquí colocamos 00 siempre es bueno colocar casos bordes a ver qué tal se comporta aquí la cantidad de pasos que queremos bueno obviamente nos queremos todos pero vamos a indicar que queremos no sé los primeros seis colocamos 5 ya que bueno vamos a ver qué tal va pero se comenzaría en cero y bueno nos tendríamos que colocar 6 ya que cuando sean igual ya está condición se cumple ya no va a seguir ejecutándose ok aquí la colocamos ahora vamos a colocar el tamaño estamos trabajando con esta que es la que tenemos por aquí la llamada dino podemos buscarla aquí la tenemos a estos pasos serían 012 sería el tamaño de dos así que aquí colocamos dos ya que finalmente la velocidad voy a colocarle por ejemplo para hacer las primeras pruebas punto 5 para que vaya lento y Bueno ahí podemos ver más claramente y esto sería todo guardamos para cargar todo Ya lo tenemos vamos a abrir aquí nuestra imagen ya que esta es la que estamos ampliando voy a abrirla aquí voy a llevarla hasta acá Y es que la tenemos claro va muy lento Pero recuerda que aquí la puedes acelerar por ejemplo colocarle un cero aquí adelante recargamos todo y ahora lo tenemos aquí va corriendo bastante rápido voy a colocarle aquí en punto 8 ahí va mucho mejor también podemos ver aquí las impresiones a ver si está haciendo lo que nosotros queremos fíjate comienza en cero cero Recuerda que le pasamos 6 vamos a contar y aquí tenemos seis es decir en los pasos de vuelta está funcionando correctamente ya que nuevamente queremos 6 aquí está devolviendo El Paso cero cero que justamente lo que queremos 00 luego vamos a cero uno cero dos bueno en este caso nos podemos ahora traer esta otra imagen que aunque no es la misma podemos tomarle aquí de referencia sería 001 y 02 justamente aquí tal cual puede ver luego queremos ya que llegamos aquí a la cuota máxima según el tamaño aquí definido el 6 en X en 2 vamos con el siguiente paso que serían 10 ya aquí cambiamos sería el x1011 y 12 Exactamente lo mismo que son los valores que tenemos aquí en este caso ya no pasa el siguiente porque queremos es solamente seis pasos si aquí colocamos 7 guardamos recargamos y colocamos aquí nuevamente nuestra imagen Aquí vamos a regresar o vamos a ir al siguiente paso que sería justamente aquí y ahí lo tuviéramos hasta el 2 entonces el algoritmo parece que está funcionando correctamente Y recuerda Bueno aquí era la importancia aquí de colocar esto en el negado y aquí recuerda colocar aquí el -1:

    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++;
      }

Para que la primera comprobación que hagamos aquí la eliminé también pues ahí validar la otra manera pero así le hice yo entonces en este punto podemos colocar el resto de los pasos Recuerda que estamos comenzando aquí en 00 esta sería vamos a ver 0 y 1 en y dos en y para colocar el resto de los pasos es muy sencillo este sería el paso el paso cero cero uno dos tres cuatro cinco seis siete serían siete pasos es decir aquí colocamos la función colocamos aquí la ya la tenemos hasta siete justamente ahí ya tenemos la animación correspondiente tal cual puedes ver funciona correctamente no tenemos ningún error y ya con esto creamos una función bastante reutilizable como te indicaba ya aquí en este punto que la creamos ya podemos también hablar un poco de eso tú puedes crear la función con la estructura que tú quieras claro está yo considero que está bastante moldeable es decir puedes adaptarla bastante bien tal cual vimos indicando a partir de qué paso quieres y cuántos pasos quieres etcétera Pero también puedes crear una función que trabaje por filas que traje por columnas etcétera todo depende de cómo te quieras organizar,

 

Recuerda que este material forma parte de mi curso completo sobre Flame Flutter y libro sobre el desarrollo de juegos en 2D con Flame.

- Andrés Cruz

In english

Andrés Cruz

Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz En Udemy

Acepto recibir anuncios de interes sobre este Blog.

!Cursos desde!

10$

En Udemy

Quedan 1d 01:37!

Udemy

!Cursos desde!

4$

En Academia

Ver los cursos

!Libros desde!

1$

Ver los libros
¡Hazte afiliado en Gumroad!