viernes, 29 de mayo de 2009

Las monedas

El tema de las monedas nos va a permitir crear un nuevo tipo de Sprite, los Sprites de fondo. Esto no es algo de PALib, si no que es algo implementado por nuestra pequeña librería.

Los sprites de fondo o 'background sprite' se moverán con el fondo, por lo que habrá que hacer también funciones que muevan el fondo.

Se ha implementado casi todo dentro de ScreenManager. La función para crear un Sprite de fondo es 'CreateBackgroundSprite'. Tiene los mismos parámetros que 'CreateSprite', lo único que el Sprite queda en una lista de sprites de fondo. También se ha preparado 'CloneBackgroundSprite' que crea un sprite idéntico ahorrando espacio en memoria.

Antes de ver las funciones, conviene resaltar que se ha usado por primera vez una clase de C++ denominada Vector. Esta clase permite tener una especie de 'array' que se puede ir cargando de forma dinámica. En este caso se ha usado de esta forma:


//ScreenManager.h
std::vector *m_backgroundSprites;


Esta es la forma de crear un vector de clases de Sprite. Más delante se ve como recorrerlo, en 'MoveRightBackgroundSprites' y en 'MoveLeftBackgroundSprites'.

Las funciones nuevas son las siguientes:


Sprite *ScreenManager::CreateBackgroundSprite(unsigned int background, unsigned int shape, unsigned int sizes, void *palette, void *sprite, int x, int y) {
return CreateBackgroundSprite(background, shape, sizes, palette, sprite, x, y, 0);
}

Sprite *ScreenManager::CreateBackgroundSprite(unsigned int background, unsigned int shape, unsigned int sizes, void *palette, void *sprite, int x, int y, int hflip) {
Sprite *newSprite = new Sprite(m_screen, background, shape, sizes, palette, sprite, x, y, hflip);
if (!m_backgroundSprites) m_backgroundSprites = new std::vector();
m_backgroundSprites->push_back(newSprite);
return newSprite;
}

Sprite *ScreenManager::CloneBackgroundSprite(Sprite *sprite) {
return CloneBackgroundSprite(sprite, sprite->GetX(), sprite->GetY());
}

Sprite *ScreenManager::CloneBackgroundSprite(Sprite *sprite, int x, int y) {
Sprite *clone = sprite->Clone(x, y);
m_backgroundSprites->push_back(clone);
return clone;
}


Y, finalmente, las funciones encargadas de mover todos los sprites de fondo de un golpe son:


void ScreenManager::MoveRightBackgroundSprites(int offset) {
unsigned int i;
for(i = 0; i < m_backgroundSprites->size(); i++) {
Sprite *sprite = (Sprite *)m_backgroundSprites->at(i);
sprite->MoveRight(offset);
}
}

void ScreenManager::MoveLeftBackgroundSprites(int offset) {
unsigned int i;
for(i = 0; i < m_backgroundSprites->size(); i++) {
Sprite *sprite = (Sprite *)m_backgroundSprites->at(i);
sprite->MoveLeft(offset);
}
}


En este punto surgió un problema y es que cuando la x se hacía negativa o mayor de 256 aparecían los sprites por el otro lado. Este tema se ha corregido creando una función nueva que permite ocultar los sprites:


void Sprite::SetVisible(int visible) {
if (!visible) {
if (PA_GetSpriteMode(m_screen, m_index_sprite) != 1) {
PA_SetSpriteMode(m_screen, m_index_sprite, 1);
PA_EnableSpecialFx(m_screen, SFX_ALPHA, 0, SFX_BG0 | SFX_BG1 | SFX_BG2 | SFX_BG3 | SFX_BD);
PA_SetSFXAlpha(m_screen, 0, 0);
}
} else if (PA_GetSpriteMode(m_screen, m_index_sprite) != 0) {
PA_SetSpriteMode(m_screen, m_index_sprite, 0);
}
}


Esta función pone el sprite totalmente transparente (Esto no es cierto del todo, Existen dos modos y en uno de ellos serán todos los sprites transparentes). Se puede utilizar desde nuestros programas y además lo utilizan las funciones SetX, SetY y SetXY si las coordenadas están fuera de la pantalla:

void Sprite::SetX(int x) {
m_x = x;
PA_SetSpriteX(m_screen, m_index_sprite, m_x);
if (m_x < 0 || m_x > 256) SetVisible(0);
else SetVisible(1);
}

void Sprite::SetY(int y) {
m_y = y;
PA_SetSpriteY(m_screen, m_index_sprite, m_y);
if (m_y < 0 || m_y > 192) SetVisible(0);
else SetVisible(1);
}

void Sprite::SetXY(int x, int y) {
m_x = x;
m_y = y;
PA_SetSpriteXY(m_screen, m_index_sprite, m_x, m_y);
if (m_x < 0 || m_x > 256) SetVisible(0);
else SetVisible(1);
}


Las monedas las hemos creado en NSMB.cpp de la siguiente manera:

Sprite *coin = topScreen->CreateBackgroundSprite(BACKGROUND_TWO, COIN, 192, 80);
coin->SetAnim(0, 3, 4);
coin->StartAnim();
topScreen->CloneBackgroundSprite(coin, 224, 88);
topScreen->CloneBackgroundSprite(coin, 248, 96);
topScreen->CloneBackgroundSprite(coin, 548, 104);


La primera línea crea una moneda (un sprite de fondo).
La segunda define los frames para la animación.
La tercera pone a girar la moneda.
Y las otras tres crean tres monedas más.

Este es el aspecto del juego en estos momentos:



¡¡Ahora solo nos falta saltar para coger esas monedas!!

Tenemos que hacer el tema de la gravedad y lo de saltar.

El código correspondiente a esta última entrega lo podéis descargar desde aquí.

Nos vemos en los comentarios.

Saludos

5 comentarios:

David Martínez Martínez dijo...

Esto marcha, poco a poco va tomando forma el proyecto. ¡Sigue así!

Anónimo dijo...

hola puede k mi comentario este fuera de lugar però el otro dia revisando los antiguos proiectos i me di cuenta de k algo falta al principio de muchos proyectos.
Tip lo k tienen los juegosde la DS donde dice nintendo presents,soni etc...
Un gran ejemplo son los juegos de Naruto.
Siento gran curiosidad por k m explikes como se hace.

Camisetas de Futbol dijo...

Estaria bien k el proximo tuto fuera sobre como poner enemigos:
Estoi muy interesado en el tema.

Inigo dijo...

Muchas gracias por los comentarios.

Es cierto que toda juego decente debe tener sus intros. Lo prepararemos.

En cuanto a lo de los enemigos, hay que pensarlo bien. Hay que crear los sprites, definir un comportamiento para cada uno, etc. algo haremos!!

Saludos

Anónimo dijo...

Tengo una sujerencia:
I si en lugar de el koopaponemos a otro personaje tipo link,o personajes de strret fighter i hacemos k para derrotar enemigos usen una espada.
Lo digo porke en los juegos de platformas se usan más personajes con armas, mientras k el koopa si es tipo mario solo derrota el enemigo con un golpeen la cabeza.