Versión: 0.47, de 10-Jul-2011


La aproximación orientada a objetos (3). MiniMiner 3: Personaje y enemigo como clases (*)

Ya habíamos creado las clases auxiliares "Hardware" y "ElementoGraf". Ahora vamos a empezar a descomponer la lógica de juego como una serie de objetos que cooperan entre sí. En este acercamiento vamos a incluir:

El diagrama de clases (sin detallar los métodos ni los atributos de cada clase de objetos) podría ser:

Y ninguna de estas tres clases es complicada de crear...

El fichero de cabecera de Presentacion podría ser así:

/*------------------------------*/
/*  Intro a la programac de     */
/*  juegos, por Nacho Cabanes   */
/*                              */
/*   Presentacion.h:            */
/*     La "presentacion" de     */
/*     Miniminer (version 0.03) */
/*     Fichero de cabecera      */
/*                              */
/*  Comprobado con:             */
/*  - DevC++ 4.9.9.2(gcc 3.4.2) */
/*    y Allegro 4.03 - WinXP    */
/*------------------------------*/
 
#ifndef Present_h
#define Present_h
 
#include "ElementoGraf.h"
#include "Hardware.h"
 
class Presentacion {
 
 public:
 
    Presentacion();
    int mostrar(Hardware h);
 
 private:
    ElementoGraf cartel;
 
};
#endif
 

Y el desarrollo podría ser así:

/*------------------------------*/
/*  Intro a la programac de     */
/*  juegos, por Nacho Cabanes   */
/*                              */
/*   Presentacion.cpp:          */
/*     La "presentacion" de     */
/*     Miniminer (version 0.03) */
/*     Fichero de desarrollo    */
/*                              */
/*  Comprobado con:             */
/*  - DevC++ 4.9.9.2(gcc 3.4.2) */
/*    y Allegro 4.03 - WinXP    */
/*------------------------------*/
 
#include "Hardware.h"
#include "ElementoGraf.h"
#include "Presentacion.h"
 
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
using namespace std;
 
/** constructor
 *  y lee los records
 */
Presentacion::Presentacion() {
    cartel.crearDesdeFichero( "miner.bmp" );
}
 
 
/** bienvenida: muestra la pantalla de bienvenida
 *  y espera una tecla
 */
int Presentacion::mostrar(Hardware h) {
    int tecla;
    // Primero muestro el cartel antiguo
    hard = h;
    hard.borrarOculta();
    cartel.moverA(0,0);
    hard.dibujarOculta(cartel);
    hard.visualizarOculta();
 
    hard.esperarTecla();
}
 

Del forma similar, el fichero de cabecera de Personaje podría ser:

/*------------------------------*/
/*  Intro a la programac de     */
/*  juegos, por Nacho Cabanes   */
/*                              */
/*   Personaje.h:               */
/*     El "personaje" de        */
/*     Miniminer (version 0.03) */
/*     Fichero de cabecera      */
/*                              */
/*  Comprobado con:             */
/*  - DevC++ 4.9.9.2(gcc 3.4.2) */
/*    y Allegro 4.03 - WinXP    */
/*------------------------------*/
 
#ifndef Personaje_h
#define Personaje_h
 
#include "ElementoGraf.h"
#include "Hardware.h"
 
class Personaje: public ElementoGraf {
 
 public:
 
    Personaje();
 
    void moverDerecha();
    void moverIzquierda();
};
 
#endif
 

Y su desarrollo:

/*------------------------------*/
/*  Intro a la programac de     */
/*  juegos, por Nacho Cabanes   */
/*                              */
/*   Personaje.cpp:             */
/*     El "personaje" de        */
/*     Miniminer (version 0.03) */
/*     Fichero de desarrollo    */
/*                              */
/*  Comprobado con:             */
/*  - DevC++ 4.9.9.2(gcc 3.4.2) */
/*    y Allegro 4.03 - WinXP    */
/*------------------------------*/
 
#include "Hardware.h"
#include "ElementoGraf.h"
#include "Personaje.h"
 
#ifdef __cplusplus
#include <cstdlib>
#include <time.h>
#else
#include <stdlib.h>
#include <time.h>
#endif
using namespace std;
 
 
/** constructor
 *  y lee los records
 */
Personaje::Personaje() {
    posX = 200;
    posY = 200;
    crearDesdeFichero( "personaje.bmp" );
}
 
 
 
/** moverDerecha: mueve el personaje hacia la derecha
 */
void Personaje::moverDerecha() {
    posX += 4;
}
 
/** moverIzquierda: mueve el personaje hacia la izquierda
 */
void Personaje::moverIzquierda() {
    posX -= 4;
}
 

Finamente, el fichero de cabecera de Enemigo sería:

/*------------------------------*/
/*  Intro a la programac de     */
/*  juegos, por Nacho Cabanes   */
/*                              */
/*   Enemigo.h:                 */
/*     El "enemigo" de          */
/*     Miniminer (version 0.03) */
/*     Fichero de cabecera      */
/*                              */
/*  Comprobado con:             */
/*  - DevC++ 4.9.9.2(gcc 3.4.2) */
/*    y Allegro 4.03 - WinXP    */
/*------------------------------*/
 
#ifndef Enemigo_h
#define Enemigo_h
 
#include "ElementoGraf.h"
#include "Hardware.h"
 
class Enemigo: public ElementoGraf {
 
 public:
 
    Enemigo();
    void mover();
 
  private:
 
    int incrX;
};
 
#endif
 

Y su desarrollo:

/*------------------------------*/
/*  Intro a la programac de     */
/*  juegos, por Nacho Cabanes   */
/*                              */
/*   Enemigo.cpp:               */
/*     El "enemigo" de          */
/*     Miniminer (version 0.03) */
/*     Fichero de desarrollo    */
/*                              */
/*  Comprobado con:             */
/*  - DevC++ 4.9.9.2(gcc 3.4.2) */
/*    y Allegro 4.03 - WinXP    */
/*------------------------------*/
 
#include "Hardware.h"
#include "ElementoGraf.h"
#include "Enemigo.h"
 
#ifdef __cplusplus
#include <cstdlib>
#include <time.h>
#else
#include <stdlib.h>
#include <time.h>
#endif
using namespace std;
 
 
/** constructor
 *  y lee los records
 */
Enemigo::Enemigo() {
    posX = 500;
    posY = 200;
    incrX = 2;
    crearDesdeFichero( "enemigo.bmp" );
}
 
 
/** mover: mueve el personaje según indique su lógica
 */
void Enemigo::mover() {
  posX += incrX;
  // Da la vuelta si llega a un extremo
  if ((posX > 570) || (posX < 30))
    incrX = -incrX;
}
 
 
 
 

Y el cuerpo del programa, que vuelve a reducir su tamaño (esta vez en 20 líneas) y a ganar en legibilidad quedaría así:

/*------------------------------*/
/*  Intro a la programac de     */
/*  juegos, por Nacho Cabanes   */
/*                              */
/*    miner02.cpp               */
/*                              */
/*  Ejemplo:                    */
/*    Primer acercamiento a     */
/*    "MiniMiner"               */
/*                              */
/*  Comprobado con:             */
/*  - DevC++ 4.9.9.2(gcc 3.4.2) */
/*    y Allegro 4.03 - WinXP    */
/*------------------------------*/
 
#include "Hardware.h"
#include "ElementoGraf.h"
#include "Personaje.h"
#include "Enemigo.h"
#include "Presentacion.h"
 
/* -------------- Constantes globales ------------- */
#define ANCHOPANTALLA 640
#define ALTOPANTALLA 480
 
/* -------------- Variables globales -------------- */
Hardware hard;
Personaje *personaje;
Enemigo *enemigo;
Presentacion *presentacion;
ElementoGraf *fragmentoSuelo;
 
int partidaTerminada;
int incrX = 4;
int incrY = 4;
int tecla;
int ySuelo = 232;
 
 
// Prototipos de las funciones que usaremos
void comprobarTeclas();
void moverElementos();
void comprobarColisiones();
void dibujarElementos();
void pausaFotograma();
void moverDerecha();
void moverIzquierda();
void lanzarPresentacion();
void moverEnemigo();
void dibujarFondo();
 
 
 
// --- Bucle principal del juego -----
void buclePrincipal() {
  partidaTerminada = false;
  do {
    comprobarTeclas();
    moverElementos();
    comprobarColisiones();
    dibujarElementos();
    pausaFotograma();
  } while (partidaTerminada != true);
}
 
 
// -- Comprobac de teclas para mover personaje o salir
void comprobarTeclas() {   
 
  if (hard.comprobarTecla(TECLA_ESC))
     partidaTerminada = true;
 
  if (hard.comprobarTecla(TECLA_DCHA))
     personaje->moverDerecha();
  else if (hard.comprobarTecla(TECLA_IZQD))
     personaje->moverIzquierda();
}
 
 
// -- Mover otros elementos del juego 
void moverElementos() {
  enemigo->mover();
}
 
 
// -- Comprobar colisiones de nuestro elemento con otros, o disparos con enemigos, etc
void comprobarColisiones() {
  // Por ahora, no hay colisiones que comprobar
}
 
 
// -- Dibujar elementos en pantalla
void dibujarElementos() {
 
  hard.borrarOculta();
  dibujarFondo();
  hard.dibujarOculta( *enemigo );
  hard.dibujarOculta( *personaje );
  hard.visualizarOculta();
}
 
 
// -- Pausa hasta el siguiente fotograma
void pausaFotograma() {
  // Para 25 fps: 1000/25 = 40 milisegundos de pausa
  hard.pausa(40);
}
 
 
// -- Funciones que no son de la logica de juego, sino de 
// funcionamiento interno de otros componentes
 
// -- Pantalla de presentacion
void lanzarPresentacion() {
  presentacion->mostrar(hard);
}
 
 
// -- Dibuja el fondo (por ahora, apenas un fragmento de suelo)
void dibujarFondo() {
  int i;
  int anchoImagen = 16;
  for (i=0; i<15; i++)
  {
      fragmentoSuelo->moverA(i*anchoImagen, ySuelo);
      hard.dibujarOculta( *fragmentoSuelo );
  }
}
 
/* -------------- Rutina de inicialización -------- */
int inicializa()
{
    hard.inicializar(640,480);
    personaje = new Personaje();
    enemigo = new Enemigo();
    presentacion = new Presentacion();
    fragmentoSuelo = new ElementoGraf();
 
    fragmentoSuelo->crearDesdeFichero("suelo.bmp");
 
   // Y termino indicando que no ha habido errores
   return 0;
}
 
 
 
/* ------------------------------------------------ */
/*                                                  */
/* -------------- Cuerpo del programa ------------- */
 
int main()
{
 
    int i,j;
 
    // Intento inicializar
    if (inicializa() != 0)
        exit(1);
 
    lanzarPresentacion();
    buclePrincipal();
 
    hard.pausa(1000);
    return 0;
}
 
            /* Termino con la "macro" que me pide Allegro */
END_OF_MAIN();
 

Anterior Siguiente