miércoles, 16 de abril de 2008

Animar nuestro Sprite

Para animar a nuestro héroe únicamente hace falta la sentencia PA_StartSpriteAnim. En ella definimos el sprite inicio y final de la animación así como la velocidad de esta.

Para controlar la animación haremos que cuando se pulse uno de los cursores el muñeco realice la animación de esa dirección, hasta que se pulse otro cursor, o no se deje de pulsar. A mi se me ha ocurrido hacerlo usando una variable que guarde el estado de la animación, con valores tipo ANIMACION_DERECHA, ANIMACION_IZQUIERDA, ANIMACION_PAUSA, ... La variable la llamaremos estadoAnimacion.
El código a incluir será:

Antes del bucle u32 estadoAnimacion = ANIMACION_PAUSA;

El if a poner en el bucle sería algo así:

        if (Pad.Held.Up) {
            if (estadoAnimacion != ANIMACION_ARRIBA) {
                estadoAnimacion = ANIMACION_ARRIBA;
                PA_StartSpriteAnim(SCREEN_TOP, HEROE_SPRITE, 3, 5, HEROE_VELOCIDAD);
                PA_SetSpriteHflip(SCREEN_TOP, HEROE_SPRITE, 0);
            }
        } else if (Pad.Held.Down) {
            if (estadoAnimacion != ANIMACION_ABAJO) {
                estadoAnimacion = ANIMACION_ABAJO;
                PA_StartSpriteAnim(SCREEN_TOP, HEROE_SPRITE, 0, 2, HEROE_VELOCIDAD);
                PA_SetSpriteHflip(SCREEN_TOP, HEROE_SPRITE, 0);
            }
        } else if (Pad.Held.Left) {
            if (estadoAnimacion != ANIMACION_IZQUIERDA) {
                estadoAnimacion = ANIMACION_IZQUIERDA;
                PA_StartSpriteAnim(SCREEN_TOP, HEROE_SPRITE, 6, 8, HEROE_VELOCIDAD);
                PA_SetSpriteHflip(SCREEN_TOP, HEROE_SPRITE, 1);
            }
        } else if (Pad.Held.Right) {
            if (estadoAnimacion != ANIMACION_DERECHA) {
                estadoAnimacion = ANIMACION_DERECHA;
                PA_StartSpriteAnim(SCREEN_TOP, HEROE_SPRITE, 6, 8, HEROE_VELOCIDAD);
                PA_SetSpriteHflip(SCREEN_TOP, HEROE_SPRITE, 0);
            }
        } else {
            estadoAnimacion = ANIMACION_PAUSA;
            PA_StopSpriteAnim(SCREEN_TOP, HEROE_SPRITE);
        }

Y con esto ya lo tenemos en movimiento.

El código quedará de la siguiente manera:

#include <PA9.h>

#include "gfx/all_gfx.h"
#include "gfx/all_gfx.c"

#include "devnintendods.h"

#define BACKGROUND_X 80
#define BACKGROUND_Y 132

#define HEROE_PALLETE 0
#define HEROE_SPRITE 0
#define HEROE_X 120
#define HEROE_Y 88
#define HEROE_VELOCIDAD 5

#define ANIMACION_PAUSA 0
#define ANIMACION_ABAJO 1
#define ANIMACION_ARRIBA 2
#define ANIMACION_IZQUIERDA 3
#define ANIMACION_DERECHA 4

int main(int argc, char ** argv) {
    PA_Init();
    PA_InitVBL();
    PA_InitText(SCREEN_BOTTOM, BACKGROUND_ZERO);

    PA_EasyBgLoad(SCREEN_TOP, BACKGROUND_TWO, fondo);
    PA_EasyBgLoad(SCREEN_TOP, BACKGROUND_THREE, agua);
    PA_InitParallaxX(SCREEN_TOP, 0, 0, 256, 0);
    PA_InitParallaxY(SCREEN_TOP, 0, 0, 256, 0);

    PA_LoadSpritePal(SCREEN_TOP, HEROE_PALLETE,(void*)heroe_Pal);
    PA_CreateSprite(SCREEN_TOP, HEROE_SPRITE, (void*)heroe_Sprite, OBJ_SIZE_16X32, COLOR_MODE_256, HEROE_PALLETE, HEROE_X, HEROE_Y);
    PA_SetSpritePrio(SCREEN_TOP, HEROE_SPRITE, BACKGROUND_TWO);

    s32 fondoX = BACKGROUND_X;
    s32 fondoY = BACKGROUND_Y;
    s32 estadoAnimacion = ANIMACION_PAUSA;

    PA_ParallaxScrollXY(SCREEN_TOP, fondoX, fondoY);
    PA_WaitForVBL();
    while  (1) {
        fondoX += Pad.Held.Right - Pad.Held.Left;
        fondoY += Pad.Held.Down - Pad.Held.Up;

        if (Pad.Held.Up) {
            if (estadoAnimacion != ANIMACION_ARRIBA) {
                estadoAnimacion = ANIMACION_ARRIBA;
                PA_StartSpriteAnim(SCREEN_TOP, HEROE_SPRITE, 3, 5, HEROE_VELOCIDAD);
                PA_SetSpriteHflip(SCREEN_TOP, HEROE_SPRITE, 0);
            }
        } else if (Pad.Held.Down) {
            if (estadoAnimacion != ANIMACION_ABAJO) {
                estadoAnimacion = ANIMACION_ABAJO;
                PA_StartSpriteAnim(SCREEN_TOP, HEROE_SPRITE, 0, 2, HEROE_VELOCIDAD);
                PA_SetSpriteHflip(SCREEN_TOP, HEROE_SPRITE, 0);
            }
        } else if (Pad.Held.Left) {
            if (estadoAnimacion != ANIMACION_IZQUIERDA) {
                estadoAnimacion = ANIMACION_IZQUIERDA;
                PA_StartSpriteAnim(SCREEN_TOP, HEROE_SPRITE, 6, 8, HEROE_VELOCIDAD);
                PA_SetSpriteHflip(SCREEN_TOP, HEROE_SPRITE, 1);
            }
        } else if (Pad.Held.Right) {
            if (estadoAnimacion != ANIMACION_DERECHA) {
                estadoAnimacion = ANIMACION_DERECHA;
                PA_StartSpriteAnim(SCREEN_TOP, HEROE_SPRITE, 6, 8, HEROE_VELOCIDAD);
                PA_SetSpriteHflip(SCREEN_TOP, HEROE_SPRITE, 0);
            }
        } else {
            estadoAnimacion = ANIMACION_PAUSA;
            PA_StopSpriteAnim(SCREEN_TOP, HEROE_SPRITE);
        }
        if (estadoAnimacion != ANIMACION_PAUSA) {
            PA_ParallaxScrollXY(SCREEN_TOP, fondoX, fondoY);
        }    
        PA_WaitForVBL();
    }
    return 0;
}


¿Qué nos queda? Lo primero que nuestro héroe no se escape del mundo que le hemos creado. PALib, de nuevo, nos ayudará a lograr el que será nuestro próximo objetivo, 'la colisión'.

Un saludo

Enlaces patrocinados
gafas de sol
infografias
Peluches
hipermetropia
despedida de soltera en Cadiz
despedida de soltera en barcelona

Sprites

El siguiente paso en nuestro juego será poner a nuestro héroe a recorrer el mundo que le hemos creado en la anterior entrega.

Como hemos hecho que lo que se mueva sea el fondo, el muñeco estará en el centro de la pantalla.

Pero ¿Qué es un Sprite? Un sprite es un elemento gráfico que se superpone a los fondos, y que gracias a las transparencias, no borra a estos. Vamos a ver nuestro primer sprite:

Muy bien. En este Sprite tenemos a nuestro héroe con las distintas posturas que tendrá en el juego. Guardaremos dicha imagen en C:\devDS\PokemonDS\source\gfx como heroe.png. Para cargar la imagen en el juego, realizaremos los siguientes pasos:
  1. Ejecutar PAGC Frontend (el que está dentro de la carpeta gfx de nuestro source)
  2. Load INI (para cargar el INI donde tenemos el fondo, que si no perdemos el fondo!)
  3. En la pestaña de Sprites cargamos la imagen heroe.png
  4. Save and Convert
Como muchos os habéis imaginado el color rosa es el color transparente, y el espacio que hay entre cada muñeco es porque la DS (o PALib) soporta los siguientes tamaños de Sprites:

8x8 16x8 32x8
8x16 16x16 32x16
8x32 16x32 32x32 64x32
32x64 64x64

En nuestro caso el héroe entraba en una caja de 16x32 y como tenemos 9 posturas, pues la imagen mide 16 x 288.
¿Dónde están las posturas mirando a la izquierda? Pues resulta que podemos rotar al sprite, así que no nos van a hacer falta (porque para este Sprite el ir a la izquierda o a la derecha es idéntico, cosa que no siempre es así).

Pongamos el código necesario. Primero, añadiremos una nueva constante a nuestro fichero devnintendods.h, que quedará así:

#define SCREEN_TOP 1
#define SCREEN_BOTTOM 0

#define BACKGROUND_ZERO 0
#define BACKGROUND_ONE 1
#define BACKGROUND_TWO 2
#define BACKGROUND_THREE 3

#define COLOR_MODE_256 1

y después así es como quedará el main.c:
// Includes
#include <pa9.h> // Include for PA_Lib
#include "gfx/all_gfx.h" #include "gfx/all_gfx.c" #include "devnintendods.h" #define BACKGROUND_X 56 #define BACKGROUND_Y 132 #define HEROE_PALLETE 0 #define HEROE_SPRITE 0 #define HEROE_X 120 #define HEROE_Y 88 int main(int argc, char ** argv) { PA_Init(); PA_InitVBL(); PA_EasyBgLoad(SCREEN_TOP, BACKGROUND_THREE, fondo); PA_InitParallaxX(SCREEN_TOP, 0, 0, 256, 0); PA_InitParallaxY(SCREEN_TOP, 0, 0, 256, 0); PA_LoadSpritePal(SCREEN_TOP, HEROE_PALLETE,(void*)heroe_Pal); PA_CreateSprite(SCREEN_TOP, HEROE_SPRITE, (void*)heroe_Sprite, OBJ_SIZE_16X32, COLOR_MODE_256, HEROE_PALLETE, HEROE_X, HEROE_Y); PA_SetSpritePrio(SCREEN_TOP, HEROE_SPRITE, BACKGROUND_TWO); s32 fondoX = BACKGROUND_X; s32 fondoY = BACKGROUND_Y; while (1) { fondoX += Pad.Held.Right - Pad.Held.Left; fondoY += Pad.Held.Down - Pad.Held.Up; if (Pad.Held.Up) { PA_SetSpriteAnim(SCREEN_TOP, HEROE_SPRITE, 4); PA_SetSpriteHflip(SCREEN_TOP, HEROE_SPRITE, 0); } if (Pad.Held.Down) { PA_SetSpriteAnim(SCREEN_TOP, HEROE_SPRITE, 0); PA_SetSpriteHflip(SCREEN_TOP, HEROE_SPRITE, 0); } if (Pad.Held.Left) { PA_SetSpriteAnim(SCREEN_TOP, HEROE_SPRITE, 6); PA_SetSpriteHflip(SCREEN_TOP, HEROE_SPRITE, 1); } if (Pad.Held.Right) { PA_SetSpriteAnim(SCREEN_TOP, HEROE_SPRITE, 6); PA_SetSpriteHflip(SCREEN_TOP, HEROE_SPRITE, 0); } PA_EasyBgScrollXY(SCREEN_TOP, BACKGROUND_THREE, fondoX, fondoY); PA_WaitForVBL(); } return 0; }

El código es muy sencillo: se carga la paleta de colores del sprite, podemos tener paletas compartidas y así ahorramos recursos, y después se crea el sprite. Si os fijáis las variables heroe_Pal y heroe_Sprite las crea el programa PAGC.

Sólo nos falta animar a nuestro héroe. Empezaremos por partes, para esta entrega con girarlo dependiendo de la dirección en que nos desplacemos será suficiente. if (Pad.Held.Left) nos indicará si se ha pulsado el cursor izquierdo, por lo que ponemos el Sprite en el primer frame de la posición izquierda y lo giramos. if (Pad.Held.Right) nos indica que hemos pulsado el cursor derecho y ponemos el frame en la primera posición que refleja el ir a la derecha. Aunque en este caso no haría falta girar el Sprite, como es posible que lo hayamos hecho al ir a la izquierda, tendremos que anular dicho giro.

Vemos una imagen del juego:

Y esto es todo. En la próxima entrega haremos que nuestro héroe mueva las piernas y los brazos.

Un saludo