viernes, 18 de diciembre de 2009

MegaMan ya dispara

Para ver a nuestro nuevo héroe disparando he creado un nuevo proyecto.

El código que he escrito lo he metido dentro de la librería devnintendods, pero no tiene que ser difícil ponerlo en otro proyecto. Por supuesto el juego está en 2D.

Se ha creado un vector en la clase ScreenManager que se denomina m_dynamicSprite. Este es el vector donde se irán añadiendo los distintos elementos dinámicos del juego. En este caso son disparos, pero podrían ser otras cosas, por ejemplo los enemigos, o las casas que se van construyendo en un juego tipo Age of Empire. Los objetos que se asocian a este array deben implementar el interface DyamicSprite. De esta forma todos tendrán la función Next.

Desde el bucle del juego, en GameManager se llama a la función Next de ScreenManager. Se hacen dos llamadas, una para la pantalla de arriba y otra para la pantalla de abajo:

void GameManager::Run() {
 bool exit = 1;
 while (exit) {
  if (m_KeypadManager) {
   if (Pad.Newpress.Up) {
    exit = m_KeypadManager->NewpressUp();
   } else if (Pad.Newpress.Left) {
    exit = m_KeypadManager->NewpressLeft();
   } else if (Pad.Newpress.Right) {
    exit = m_KeypadManager->NewpressRight();
   } else if (Pad.Newpress.Down) {
    exit = m_KeypadManager->NewpressDown();
   } else if (Pad.Held.Up) {
    exit = m_KeypadManager->HeldUp();
   } else if (Pad.Held.Left) {
    exit = m_KeypadManager->HeldLeft();
   } else if (Pad.Held.Right) {
    exit = m_KeypadManager->HeldRight();
   } else if (Pad.Held.Down) {
    exit = m_KeypadManager->HeldDown();
   } else {
    exit = m_KeypadManager->NoKey();
   }
  }
  m_TopScreenManager->Next();
  m_BottomScreenManager->Next();
  exit = exit && m_KeypadManager->BeforeVBL();
  PA_WaitForVBL();
 }
}

ScreenManager es la que recorre el array y llama a todas las funciones Next, independientemente del tipo de objeto que sea. En nuestro caso es siempre un objeto de tipo Disparo.

void ScreenManager::Next() {
 unsigned int i;
 for (i = 0; i < m_dynamicSprites->size(); i++) {
  DynamicSprite *dynamicSprite = m_dynamicSprites->at(i);
  dynamicSprite->Next(this);
 }
}

void ScreenManager::EraseDynamicSprite(DynamicSprite *dynamicSprite) {
 unsigned int i;
 for (i = 0; i < m_dynamicSprites->size(); i++) {
  DynamicSprite *dynamic = m_dynamicSprites->at(i);
  if (dynamic == dynamicSprite) {
   m_dynamicSprites->erase(m_dynamicSprites->begin() + i);
   delete dynamicSprite;
  }
 }
}

Al pulsar la tecla de disparar (he puesto la flecha para arriba porque en mi emulador no funciona la A) se crea un disparo y se añade al array. La función Next del disparo es la que se encargará de mover la bala en la dirección correcta y cuando llegue al final de la pantalla destruir el propio objeto.

bool Disparo::Next(void *screenManager) {
 if (m_direccion == DIRECCION_IZQUIERDA) {
  int x = this->MoveLeft(VELOCIDAD);
  if (x < 0) this->Stop(screenManager);
 } else if (m_direccion == DIRECCION_DERECHA) {
  int x = this->MoveRight(VELOCIDAD);
  if (x > 256) this->Stop(screenManager);
 }
 return 1;
}

void Disparo::Stop(void *screenManager) {
 ScreenManager *sm = (ScreenManager *)screenManager;
 sm->EraseDynamicSprite(this);
}

Y esto es todo. Si disparáis más de 100 veces deja de disparar. He probado y todos los destructores de las clases se ejecutan y la función PA_DeleteSprite también, pero como se ha comentado en algún post anterior, este tema parece que no va bien.


En el próximo post veremos como disparar un sólo proyectil. El proyecto se puede descargar de aquí.

Saludos

No hay comentarios: