jueves, 13 de noviembre de 2008

El reflejo sobre el lago

Por fin llegamos al reflejo de nuestro personaje en el lago. Lo prometimos en la primera entrega de este blog. Este efecto es una de las cosas que dará calidad a nuestro juego. Parece difícil, pero como todo en esto del software, es muy sencillo, sólo hay que conocer la API de PALib y echarle imaginación.

PALib contiene funciones para que un Sprite se visualice con cierta transparencia, es decir, un reflejo en un lago no va a ser una imagen tan nítida como el original. ¡¡¡Esta función la usaremos!!!

También tenemos una función que posibilita girar un Sprite, (que ya la hemos utilizado), y resulta que el reflejo no es más que nuestro Sprite girado verticalmente. ¡¡¡ Esta también la usaremos!!!

Y Por último, el reflejo se verá sobre el agua, no sobre la hierba. Así que el Sprite andará sobre la capa del agua, por debajo del fondo, y alehop!!!, ya tenemos nuestro reflejo.

¡Parecía imposible!

1. PA_CreateSprite(SCREEN_TOP, HEROE_REFLEJO_SPRITE, (void*)heroe_Sprite, OBJ_SIZE_16X32, COLOR_MODE_256, HEROE_PALLETE, HEROE_X, HEROE_Y + 8);
2. PA_SetSpritePrio(SCREEN_TOP, HEROE_REFLEJO_SPRITE, BACKGROUND_THREE);
3. PA_SetSpriteVflip(SCREEN_TOP, HEROE_REFLEJO_SPRITE, 1);
4. PA_SetSpriteMode(SCREEN_TOP, HEROE_REFLEJO_SPRITE, 1);
5. PA_EnableSpecialFx(SCREEN_TOP, SFX_ALPHA, 0, SFX_BG0 | SFX_BG1 | SFX_BG2 | SFX_BG3 | SFX_BD);
6. PA_SetSFXAlpha(SCREEN_TOP, 12, 15);

Vamos a explicar paso a paso:

En 1 cargamos a nuestro héroe pero con el identificador HEROE_REFLEJO_SPRITE.
En 2 mandamos el reflejo a la capa sobre el agua.
En 3 giramos verticalmente el Sprite.
En 4 - 6 habilitamos la transparencia.
Y luego no olvidarnos de que al mover a nuestro héroe movamos también a su reflejo.



Aquí os dejo el código (Como siempre, esta es la forma que me he inventado. No creo que exista una función en PALib que cree una sombra de forma automática, pero...):

#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_REFLEJO_SPRITE 1
#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

#define ESPACIO_LIBRE 0

u8 obtenerBaldosa(s32 x, s32 y);

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

PA_EasyBgLoad(SCREEN_TOP, BACKGROUND_TWO, fondo);
PA_EasyBgLoad(SCREEN_TOP, BACKGROUND_THREE, agua);
PA_EasyBgLoad(SCREEN_TOP, BACKGROUND_ONE, sobre_fondo);

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

PA_CreateSprite(SCREEN_TOP, HEROE_REFLEJO_SPRITE, (void*)heroe_Sprite, OBJ_SIZE_16X32, COLOR_MODE_256, HEROE_PALLETE, HEROE_X, HEROE_Y + 8);
PA_SetSpritePrio(SCREEN_TOP, HEROE_REFLEJO_SPRITE, BACKGROUND_THREE);
PA_SetSpriteVflip(SCREEN_TOP, HEROE_REFLEJO_SPRITE, 1);
PA_SetSpriteMode(SCREEN_TOP, HEROE_REFLEJO_SPRITE, 1);
PA_EnableSpecialFx(SCREEN_TOP, SFX_ALPHA, 0, SFX_BG0 | SFX_BG1 | SFX_BG2 | SFX_BG3 | SFX_BD);
PA_SetSFXAlpha(SCREEN_TOP, 12, 15);

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

PA_InitParallaxX(SCREEN_TOP, 0, 256, 256, 0);
PA_InitParallaxY(SCREEN_TOP, 0, 256, 256, 0);

PA_ParallaxScrollXY(SCREEN_TOP, fondoX, fondoY);
PA_WaitForVBL();
//PA_InitText(SCREEN_BOTTOM, BACKGROUND_ZERO); // para debugear!!
while (1) {
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);

PA_StartSpriteAnim(SCREEN_TOP, HEROE_REFLEJO_SPRITE, 3, 5, HEROE_VELOCIDAD);
PA_SetSpriteHflip(SCREEN_TOP, HEROE_REFLEJO_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);

PA_StartSpriteAnim(SCREEN_TOP, HEROE_REFLEJO_SPRITE, 0, 2, HEROE_VELOCIDAD);
PA_SetSpriteHflip(SCREEN_TOP, HEROE_REFLEJO_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);

PA_StartSpriteAnim(SCREEN_TOP, HEROE_REFLEJO_SPRITE, 6, 8, HEROE_VELOCIDAD);
PA_SetSpriteHflip(SCREEN_TOP, HEROE_REFLEJO_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);

PA_StartSpriteAnim(SCREEN_TOP, HEROE_REFLEJO_SPRITE, 6, 8, HEROE_VELOCIDAD);
PA_SetSpriteHflip(SCREEN_TOP, HEROE_REFLEJO_SPRITE, 0);
}
} else {
estadoAnimacion = ANIMACION_PAUSA;
PA_StopSpriteAnim(SCREEN_TOP, HEROE_SPRITE);
PA_StopSpriteAnim(SCREEN_TOP, HEROE_REFLEJO_SPRITE);
}
if (estadoAnimacion != ANIMACION_PAUSA) {
s32 x = fondoX + Pad.Held.Right - Pad.Held.Left;
s32 y = fondoY + Pad.Held.Down - Pad.Held.Up;
u8 baldosa = obtenerBaldosa(x + HEROE_X + 8, y + HEROE_Y + 16);
baldosa |= obtenerBaldosa(x + HEROE_X, y + HEROE_Y + 16);
baldosa |= obtenerBaldosa(x + HEROE_X + 8, y + HEROE_Y + 8);
baldosa |= obtenerBaldosa(x + HEROE_X, y + HEROE_Y + 8);
//PA_OutputText(SCREEN_BOTTOM, 0, 6, "baldosa: %d ", baldosa); // para debugear!!
if (baldosa == ESPACIO_LIBRE) {
fondoX = x;
fondoY = y;
PA_ParallaxScrollXY(SCREEN_TOP, fondoX, fondoY);
} else {
estadoAnimacion = ANIMACION_PAUSA;
}
}
PA_WaitForVBL();
}
return 0;
}

u8 obtenerBaldosa(s32 x, s32 y) {
return mapa_Map[((y>>3) * 92) + (x>>3)];
}


Este mismo efecto se puede hacer sobre otro tipo de suelo y da un aspecto de suelo brillante muy chulo.

En la próxima entrega crearemos algún efecto más para la portada del juego y así vamos dando forma a los últimos detalles de nuestro juego.

Saludos

5 comentarios:

Anónimo dijo...

Ey!que alegria que sigas con la pagina,es genial tio,me encanta,sigue con ella que aqui tienes a un fiel lector,gracias!!

Anónimo dijo...

estupendo! un efecto muy real, muchas gracias, sigue asi!

Anónimo dijo...

no sabia ke los juegos de ds se hacian asi... es muy buena la idea de enseñar a la gente a crear juegos para ds. espero ke sigas con la web un saludo.

Inigo dijo...

Gracias por los comentarios!!!

Me animan mucho a seguir con el blog.

Saludos

David Martínez Martínez dijo...

Hola, ya hace casi un mes que no posteas algo nuevo. ¡Anímate! Cosas del stylus por ejemplo, estarían muy interesantes.

Saludos.