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

lunes, 10 de noviembre de 2008

Ultimos efectos gráficos

En estos momentos el juego está ya muy avanzado, únicamente tenemos el pequeño problemilla, de que nuestro héroe se sube a los árboles y a los setos, y eso no puede ser.

Para arreglar esto jugaremos con las capas que nos da PALib. Recordemos que tenemos cuatro posibles fondos y que nuestros Sprites (en este caso nuestro héroe) puede andar por encima o por debajo de ellas.

Lo primero de todo es crear una imagen que sea una copia de la imagen fondo y quitar todo lo que nuestro personaje puede pisar: el camino, las flores, la parte inferior de las casas y de lo árboles. Esta es una imagen de como he ido borrando todos esos elementos de la imagen:


NOTA. Cuando decimos pisar no nos referimos a pisar con los pies, si no todo el Sprite, cabeza incluida.

La imagen resultante será esta, que la denominaremos sobre_fondo.png:

Y para cargar la imagen tendremos que cargarla con el gfx, volver a generar y finalmente añadir una línea y modificar dos en nuestro código:

Añadimos: PA_EasyBgLoad(SCREEN_TOP, BACKGROUND_ONE, sobre_fondo);

y modificamos:
PA_InitParallaxX(SCREEN_TOP, 0, 256, 256, 0);
PA_InitParallaxY(SCREEN_TOP, 0, 256, 256, 0);

Y este el el resultado, nuestro héroe quedará oculto bajo los árboles y detrás de los tejados:

Para la próxima entrega el efecto sobre el lago!!!!

Saludos

Enlaces patrocinados:

viernes, 7 de noviembre de 2008

Un pequeño respiro

Muy buenas

El mes de octubre no he podido actualizar el blog, pero prometo seguir con él en cuanto me sea posible. Estoy muy agradecido a las personas que han dejado comentarios y que me animan a seguir con el blog.

Pronto tendremos más!!!