Ir al contenido

publicidad
publicidad

Foto

Curso MM: 18 Juego de ejemplo : Space Out


Este tema ha sido archivado. Esto significa que no puedes responder en este tema.
No hay respuestas en este tema

#1

Escrito 22 agosto 2009 - 17:46

Juego de ejemplo : Space Out

SpaceOut.h , SpaceOut.cpp

Éste juego es un matamarcianos muy sencillo que se va a ir mejorando hasta la versión 4 en las siguientes Horas.

Añadiendo una última característica a la clase Sprite de GameEngine

La característica es que un sprite pueda crear otro sprite de forma automática. Por ejemplo un alien disparando un misil. El misil debe aparecer como saliendo del alien y por lo tanto debe conocer sus datos de posición. Además el misil será único para cada alien ya que cada uno dispara un misil distinto. Se trata de crear un sprite basándose en las propiedades de otro sprite.

El sprite que debe ser creado es específico de cada juego, no puede hacerse de forma genérica. Por lo tanto no puede hacerse dentro de la clase Sprite, aunque ésta si puede proporcionar el sistema para hacerlo posible.

Ahora tendremos una nueva acción de sprite llamada SA_ADDSPRITE:

[code:1]typedef WORD SPRITEACTION;
const SPRITEACTION SA_NONE = 0x0000L,
SA_KILL = 0x0001L,
SA_ADDSPRITE = 0x0002L;[/code]


La acción de sprite SA_ADDSPRITE es un método especial que es llamado en el objeto Sprite en el cual se aplica la acción. Éste método es AddSprite():

[code:1]virtual Sprite* AddSprite();[/code]

Se le llama para permitir a un sprite añadir un nuevo sprite al motor del juego. Los elementos específicos del nuevo dependen de cada juego. La versión AddSprite() de la clase Sprite está vacía:

[code:1]Sprite* Sprite::AddSprite()
{
return NULL;
}[/code]

Hay que derivar la clase para cada juego que hagamos y proveer nuestra propia clase AddSprite().

SA_ADDSPRITE y AddSprite() entran en juego en GameEngine::UpdateSprites() que debe comprobar la presencia de la acción SA_ADDSPRITE y si la encuentra llamar a AddSprite(). El valor devuelto se pasa a la función AddSprite() del motor del juego que mete el sprite en la lista.

Construyendo el juego

En éste juego tenemos una clase Sprite propia que se define en AlienSprite.h y está derivada de la clase Sprite:

[code:1]1: #pragma once
2:
3: //-----------------------------------------------------------------
4: // Include Files
5: //-----------------------------------------------------------------
6: #include
7: #include "Sprite.h"
8:
9: //-----------------------------------------------------------------
10: // AlienSprite Class
11: //-----------------------------------------------------------------
12: class AlienSprite : public Sprite
13: {
14: public:
15: // Constructor(s)/Destructor
16: AlienSprite(Bitmap* pBitmap, RECT& rcBounds,
17: BOUNDSACTION baBoundsAction = BA_STOP);
18: virtual ~AlienSprite();
19:
20: // General Methods
21: virtual SPRITEACTION Update();
22: virtual Sprite* AddSprite();
23: };[/code]


Se declara un constructor y un destructor. Hay dos métodos de Sprite que AlienSprite sobrescribe : Update() y AddSprite(). Los dos le dan a ésta clase su funcionalidad única y diferente de la clase Sprite. Veamos su funcionalidad en AlienSprite.cpp:

[code:1]1: Sprite* AlienSprite::AddSprite()
2: {
3: // Crear un nuevo sprite de misil.
4: RECT rcBounds = { 0, 0, 640, 410 };
5: RECT rcPos = GetPosition();
6: Sprite* pSprite = NULL;
7: if (GetBitmap() == _pBlobboBitmap)
8: {
9: // Si el que ha disparado es un Blobbo creamos un misil tipo Blobbo.
10: pSprite = new Sprite(_pBMissileBitmap, rcBounds, BA_DIE);
11: pSprite->SetVelocity(0, 7);
12: }
13: else if (GetBitmap() == _pJellyBitmap)
14: {
15: // Jelly missile
16: pSprite = new Sprite(_pJMissileBitmap, rcBounds, BA_DIE);
17: pSprite->SetVelocity(0, 5);
18: }
19: else
20: {
21: // Timmy missile
22: pSprite = new Sprite(_pTMissileBitmap, rcBounds, BA_DIE);
23: pSprite->SetVelocity(0, 3);
24: }
25:
26: // Ponemos la posición del sprite y hacemos que la función devuelva el puntero al sprite creado.
27: pSprite->SetPosition(rcPos.left + (GetWidth() / 2), rcPos.bottom);
28: return pSprite;
29: }[/code]


Con ésta función un sprite de un alien crea un sprite de misil. Se crea un misil diferente para cada alien (comprueba primero el nombre de la imagen). La posición se pone justo debajo del alien. Y al final se devuelve el handle del sprite para que el motor lo introduzca en la lista. Ahora vemos el método Update(), que se encarga de poner la acción SA_ADDSPRITE de forma aleatoria en los sprites:

[code:1]1: SPRITEACTION AlienSprite::Update()
2: {
3: // Llamamos al método base Update().
4: SPRITEACTION saSpriteAction;
5: saSpriteAction = Sprite::Update();
6:
7: // Miramos si el alien debería lanzar un misil.
8: if ((rand() % (_iDifficulty / 2)) == 0)
9: saSpriteAction |= SA_ADDSPRITE;
10:
11: return saSpriteAction;
12: }[/code]


Ésta función lo primero que hace es llamar al método Update() del motor del juego para que se actualice el sprite de forma correcta. Luego decide de forma aleatoria si crea un misil.

Ahora vemos la función SpriteCollision(). Primero se comprueba el choque entre el misil del jugador y los aliens. Si sucede suena una explosión ,se eliminan los dos sprites y se crea un sprite de explosión. Se incrementa la puntuación y se incrementa la dificultad. Luego viene comprobar la colisión entre un misil de alien y el coche. Suena una explosión, se elimina el sprite del misil y se crea una explosión en la posición del coche. El sprite del coche se devuelve a la posición inicial. Tras ésto viene el chequeo del número de vidas para ver si se ha acabado el juego.

SpriteDying() se llama cuando un sprite se destruye. En éste juego se usa para crear pequeñas explosiones cuando un misil de alien es destruido.

El resto es bastante sencillo de entender. Pongo aquí lo más interesante.

[code:1]BOOL SpriteCollision(Sprite* pSpriteHitter, Sprite* pSpriteHittee)
{
// Comprobar si un misil del jugador y un alien han chocado.
Bitmap* pHitter = pSpriteHitter->GetBitmap();
Bitmap* pHittee = pSpriteHittee->GetBitmap();
if ((pHitter == _pMissileBitmap && (pHittee == _pBlobboBitmap ||
pHittee == _pJellyBitmap || pHittee == _pTimmyBitmap)) ||
(pHittee == _pMissileBitmap && (pHitter == _pBlobboBitmap ||
pHitter == _pJellyBitmap || pHitter == _pTimmyBitmap)))
{
// Play the small explosion sound
PlaySound((LPCSTR)IDW_LGEXPLODE, _hInstance, SND_ASYNC |
SND_RESOURCE);

// Kill both sprites
pSpriteHitter->Kill();
pSpriteHittee->Kill();

// Create a large explosion sprite at the alien's position
RECT rcBounds = { 0, 0, 600, 450 };
RECT rcPos;
if (pHitter == _pMissileBitmap)
rcPos = pSpriteHittee->GetPosition();
else
rcPos = pSpriteHitter->GetPosition();
Sprite* pSprite = new Sprite(_pLgExplosionBitmap, rcBounds);
pSprite->SetNumFrames(8, TRUE);
pSprite->SetPosition(rcPos.left, rcPos.top);
_pGame->AddSprite(pSprite);

// Update the score
_iScore += 25;
_iDifficulty = max(80 - (_iScore / 20), 20);
}

// Comprobar si un misil alien ha chocado con el coche.
if ((pHitter == _pCarBitmap && (pHittee == _pBMissileBitmap ||
pHittee == _pJMissileBitmap || pHittee == _pTMissileBitmap)) ||
(pHittee == _pCarBitmap && (pHitter == _pBMissileBitmap ||
pHitter == _pJMissileBitmap || pHitter == _pTMissileBitmap)))
{
// Play the large explosion sound
PlaySound((LPCSTR)IDW_LGEXPLODE, _hInstance, SND_ASYNC |
SND_RESOURCE);

// Kill the missile sprite
if (pHitter == _pCarBitmap)
pSpriteHittee->Kill();
else
pSpriteHitter->Kill();

// Create a large explosion sprite at the car's position
RECT rcBounds = { 0, 0, 600, 480 };
RECT rcPos;
if (pHitter == _pCarBitmap)
rcPos = pSpriteHitter->GetPosition();
else
rcPos = pSpriteHittee->GetPosition();
Sprite* pSprite = new Sprite(_pLgExplosionBitmap, rcBounds);
pSprite->SetNumFrames(8, TRUE);
pSprite->SetPosition(rcPos.left, rcPos.top);
_pGame->AddSprite(pSprite);

// Move the car back to the start
_pCarSprite->SetPosition(300, 405);

// See if the game is over
if (--_iNumLives == 0)
{
// Play the game over sound
PlaySound((LPCSTR)IDW_GAMEOVER, _hInstance, SND_ASYNC |
SND_RESOURCE);
_bGameOver = TRUE;
}
}

return FALSE;
}[/code]

[code:1]void SpriteDying(Sprite* pSprite)
{
// Comprobar si un misil alien está muriendo.
if (pSprite->GetBitmap() == _pBMissileBitmap ||
pSprite->GetBitmap() == _pJMissileBitmap ||
pSprite->GetBitmap() == _pTMissileBitmap)
{
// Hacer sonar una pequeña explosión.
PlaySound((LPCSTR)IDW_SMEXPLODE, _hInstance, SND_ASYNC |
SND_RESOURCE | SND_NOSTOP);

// Crear un sprite de explosión pequeña en la posición del misil.
RECT rcBounds = { 0, 0, 600, 450 };
RECT rcPos = pSprite->GetPosition();
Sprite* pSprite = new Sprite(_pSmExplosionBitmap, rcBounds);
pSprite->SetNumFrames(8, TRUE);
pSprite->SetPosition(rcPos.left, rcPos.top);
_pGame->AddSprite(pSprite);
}
}[/code]


[code:1]void AddAlien()
{
// Create a new random alien sprite
RECT rcBounds = { 0, 0, 600, 410 };
AlienSprite* pSprite;
switch(rand() % 3)
{
case 0:
// Blobbo
pSprite = new AlienSprite(_pBlobboBitmap, rcBounds, BA_BOUNCE);
pSprite->SetNumFrames(8);
pSprite->SetPosition(((rand() % 2) == 0) ? 0 : 600, rand() % 370);
pSprite->SetVelocity((rand() % 7) - 2, (rand() % 7) - 2);
break;
case 1:
// Jelly
pSprite = new AlienSprite(_pJellyBitmap, rcBounds, BA_BOUNCE);
pSprite->SetNumFrames(8);
pSprite->SetPosition(rand() % 600, rand() % 370);
pSprite->SetVelocity((rand() % 5) - 2, (rand() % 5) + 3);
break;
case 2:
// Timmy
pSprite = new AlienSprite(_pTimmyBitmap, rcBounds, BA_WRAP);
pSprite->SetNumFrames(8);
pSprite->SetPosition(rand() % 600, rand() % 370);
pSprite->SetVelocity((rand() % 7) + 3, 0);
break;
}

// Add the alien sprite
_pGame->AddSprite(pSprite);
}[/code]

Código fuente


Este tema ha sido archivado. Esto significa que no puedes responder en este tema.
publicidad
publicidad