POO 2011 Introduccion Al Desarrollo de Videojuegos

12
Universidad Nacional del Litoral Facultad de Ingeniería y Ciencias Hídricas Departamento de Informática Ingeniería Informática PROGRAMACIÓN ORIENTADA A OBJETOS Introducción al desarrollo de Videojuegos Pablo Abratte [email protected] Última Revisión: 16/11/11

Transcript of POO 2011 Introduccion Al Desarrollo de Videojuegos

Page 1: POO 2011 Introduccion Al Desarrollo de Videojuegos

5/17/2018 POO 2011 Introduccion Al Desarrollo de Videojuegos - slidepdf.com

http://slidepdf.com/reader/full/poo-2011-introduccion-al-desarrollo-de-videojuegos 1/12

 

Universidad Nacional del Litoral

Facultad de Ingeniería y Ciencias HídricasDepartamento de Informática

Ingeniería Informática

PROGRAMACIÓN ORIENTADAA OBJETOS

Introducción al desarrollode Videojuegos

Pablo [email protected]

Última Revisión: 16/11/11

Page 2: POO 2011 Introduccion Al Desarrollo de Videojuegos

5/17/2018 POO 2011 Introduccion Al Desarrollo de Videojuegos - slidepdf.com

http://slidepdf.com/reader/full/poo-2011-introduccion-al-desarrollo-de-videojuegos 2/12

 

Introducción al desarrollo de videojuegos

En este texto abordaremos el desarrollo completo de un videojuego simple para ex-plicar cuestiones básicas relacionadas con la implementación de los mismos. Enprimer lugar, se diseñarán las clases encargadas de representar la lógica del juego,independientemente de cualquier tipo de interface. Luego, nos adentraremos en losdetalles de implementación de gráficos, manejo de eventos y otros aspectos espe-cíficos de un videojuego.

Diseño del videojuego Snake

El videojuego que desarrollaremos es un clon del clásico y famoso Snake que con-siste en una víbora que se desplaza a través de un nivel o laberinto evitando chocar

con las paredes y consumiendo comida que hace aumentar su longitud. En la Figu-ra 1 puede observarse una captura del juego terminado.

Figura 1. Captura de clon del juego Snake.

Para representar los niveles del juego, utilizaremos una matriz de enteros en la quecada celda tomará distintos valores según esté vacía, represente una pared o con-tenga comida, como puede observarse en la Figura 2. Por otro lado, la víbora serárepresenta como una lista de las celdas que la misma ocupa dentro de la matriz, enel ejemplo de la Figura 2, éstas son las celdas: (2;5), (2;4), (2;3), (2;2), (3;2), etc.

Figura 2. Matriz utilizada para representar un nivel del juego.

Pág 1 de 12

Page 3: POO 2011 Introduccion Al Desarrollo de Videojuegos

5/17/2018 POO 2011 Introduccion Al Desarrollo de Videojuegos - slidepdf.com

http://slidepdf.com/reader/full/poo-2011-introduccion-al-desarrollo-de-videojuegos 3/12

 

En la Figura 3 se observa el diagrama de clases propuesto para el diseño del juego.La clase Juego estará compuesta de objetos de tipo Vibora y Nivel y será la encar-gada de manejar tanto la lógica del juego como la entrada y salida del mismo.

Dejarémos el análisis de la clase juego para la sección final y veremos primero lasclases encargadas de representar el juego a nivel lógico.

Figura 3. Diagrama de clases del diseño del juego.

El constructor de la clase Nivel leerá desde un archivo de texto la matriz que espe-cificará cuales celdas están vacías y cuales corresponden a secciones de las pare-des. La clase tendrá, además, la responsabilidad de generar comida en posicionesaleatorias de la matriz que se encuentren vacías, y poseerá un método para averi-

guar el contenido de una celda determinada.Los métodos de la clase Vibora permitirán cambiar su dirección de movimiento, mo-verla, saber si aún sigue viva, y conocer su longitud o las celdas que ocupa dentrodel nivel.

Mostraremos, a continuación, algunos de los detalles de implementación de la claseVibora. Como mencionamos anteriormente, la víbora es representada mediante unalista de las celdas que ocupa en la matriz que representa al nivel. Cada celda esidentificada mediante dos enteros que indican su posición (fila y columna) dentro dela matriz. Para simplificar el almacenamiento y la operatoria de dichas celda, crea-remos una estructura llamada Coord2i para representarlas. La declaración e imple-mentación de dicha clase es mostrada a continuación a continuación.

Pág 2 de 12

Page 4: POO 2011 Introduccion Al Desarrollo de Videojuegos

5/17/2018 POO 2011 Introduccion Al Desarrollo de Videojuegos - slidepdf.com

http://slidepdf.com/reader/full/poo-2011-introduccion-al-desarrollo-de-videojuegos 4/12

 

struct Coord2i{  int x, y;

Coord2i(int i, int j);Coord2i operator+(const Coord2i &c);bool operator==(const Coord2i &c);

};

// constructor que recibe los valores de las coordendasCoord2i::Coord2i(int i, int j):x(i),y(j){}

// permite sumar coordenadas componente a componente// devuelve un objeto de tipo Coord2i con// la suma de las coordenadasCoord2i Coord2i::operator+(const Coord2i &c){  return Coord2i(x+c.x, y+c.y);}

// devuelve si las coordendas de las celdas son iguales// comparando componente a componentebool Coord2i::operator==(const Coord2i &c){  return x==c.x && y==c.y;}

La estructura posee dos valores enteros para representar la fila y columna de unacelda y se han sobrecargado, además, los operadores de suma y comparación. Laoperación de suma será útil para encontrar celdas vecinas a partir de una celda de-terminada y un desplazamiento, mientras que la comparación servirá para revisarque, al moverse, la víbora no choque con ninguna de las celdas que la conforman.

En el recuadro de código siguiente puede observarse la declaración de la clase Vi-bora. Esta clase posee un vector dinámico con las celdas que la víbora ocupa den-tro del nivel, ordenadas desde la cola, que se encuentra en la posición 0, a la celdade la cabeza que ocupa la ultima posición del vector. Además, guarda un puntero al

nivel actual, que deberá ser pasado al constructor y será utilizado para preguntar elcontenido de las celdas antes de moverse. La dirección actual y la próxima direc-ción en la que se realizará el movimiento serán de tipo Coord2i y el usuario podráespecificar la dirección del movimiento mediante llamadas a CambiarDirección(...)que podrá ser llamada pasándole como parámetro alguno de los cuatro valoresconstantes dispuestos por la clase. A su vez, la función Mover() se encargará dehacer efectivo el movimiento. La clase no manejará la velocidad del movimiento yaque la misma será responsabilidad de la clase Juego. Otras funciones de la clasepermiten conocer el largo de la vibora y si aún esta viva, es decir, no ha colisionadocon el nivel o consigo misma.

class Vibora {

  private:  bool estaViva;

vector<Coord2i> celdas;Coord2i direccionActual, proxDireccion;Nivel *nivel;

  bool ChocaraConSigoMisma(); 

public:  static const Coord2i ARRIBA;  static const Coord2i ABAJO;  static const Coord2i DERECHA;  static const Coord2i IZQUIERDA; 

Vibora(Nivel *n);  void Mover();  void CambiarDireccion(Coord2i nuevaDir);  bool EstaViva();

Pág 3 de 12

Page 5: POO 2011 Introduccion Al Desarrollo de Videojuegos

5/17/2018 POO 2011 Introduccion Al Desarrollo de Videojuegos - slidepdf.com

http://slidepdf.com/reader/full/poo-2011-introduccion-al-desarrollo-de-videojuegos 5/12

 

  unsigned Largo();Coord2i GetCelda(unsigned i);

};

const Coord2i Vibora::ARRIBA(0,-1);

const Coord2i Vibora::ABAJO(0,1);

const Coord2i Vibora::DERECHA(1,0);

const Coord2i Vibora::IZQUIERDA(-1,0);

Uno de los procedimientos más importantes es el algoritmo de movimiento de la vi-bora, el cual será explicado a continuación. Como se mencionó anteriormente, elusuario puede especificar la dirección del movimiento llamando a la funciónCam-biarDirección(...) con alguna de las cuatro constantes de dirección especificadas porla clase. Dicha dirección indicará el movimiento de la cabeza la cabeza de la vibora,y las celdas restantes simplemente la seguirán, pasando por las mismas posicionesque esta.

En un caso normal, en el que la cabeza de la vibora se desplaza hacia una posición

libre, cada una de las celdas empezando por la de la cola toma la posición de la cel-da que le sigue en la secuencia, así hasta llegar a la cabeza, la cual será desplaza-da a la nueva posición que se encuentra vacía. Este procedimiento es ilustrado enla Figura 4.

Figura 4. Secuencia de movimiento de la víbora.

El siguiente código corresponde a la función encargada del movimiento de la vivora,dicha función será llamada por el juego cuando sea el momento de que la víbora semueva.

void Vibora::Mover(){  if(!estaViva) return; 

direccionActual=proxDireccion;  // calcula la celda a la que se movera la cabeza

Coord2i proxCelda(celdas[celdas.size()-1]+direccionActual); 

// si va a chocar con si misma, muere

  if(ChocaraConSigoMisma()){estaViva=false;  return;  } 

// averiguamos el contenido de la proxima celda  int contenidoProxCelda=nivel->QueHayEnCelda(proxCelda); 

if(contenidoProxCelda==Nivel::PARED){// en la prox posicion hay una pared

  estaViva=false;  return;  }else if(contenidoProxCelda==Nivel::COMIDA){

// hay comida en la proxima celda// la vibora aumenta su tamano agregando una celda

  celdas.push_back(proxCelda);  nivel->ConsumirComida(proxCelda);

Pág 4 de 12

Page 6: POO 2011 Introduccion Al Desarrollo de Videojuegos

5/17/2018 POO 2011 Introduccion Al Desarrollo de Videojuegos - slidepdf.com

http://slidepdf.com/reader/full/poo-2011-introduccion-al-desarrollo-de-videojuegos 6/12

 

  }else{  // la posicion siguiente esta vacia

// mueve cada celda un lugar hacia adelante  for(unsigned i=0;i<celdas.size()-1;i++){  celdas[i]=celdas[i+1];  }  celdas[celdas.size()-1]=proxCelda;  }

}

La función actualiza la dirección actual del movimiento según la variable proxDirec-cion, que será alterada por el usuario llamando a la función CambiarDirección(...).Luego se calculará cual es la próxima casilla a la que la cabeza de la vibora debemoverse sumando la celda actual de la cabeza con el desplazamiento especificadopor la dirección de movimiento. Si en la nueva posición ya existe otra celda de la ví-bora, esta debe morir ya que colisiona consigo misma, la función miembro Choca-ConsigoMisma() realiza esta comprobación comparando las coordenadas de lanueva celda con las de cada una de las celdas existentes utilizando el operador ==de la clase Coord2i .

En caso de que la víbora pueda mover sin colisionar con ella misma, resta consultaral nivel por el contenido de la próxima celda. Si en dicha celda se encuentra una pa-red, la víbora debe morir ya que colisionará con el nivel. Si por el contrario hay co-mida en la próxima, se le debe indicar al nivel que la misma será consumida por lavíbora para que la borre y genere nueva comida en otra posición. Al consumir comi-da, la víbora aumenta su tamaño en celdas, agregando una nueva celda en el próxi-mo lugar al que se desplazará, sin necesidad de desplazar las anteriores. Finalmen-te, si la posición que se debe ocupar está vacía, se realiza el procedimiento de mo-vimiento descrito anteriormente recorriendo las celdas de la víbora con un bucle.

Las funciones de la clase Nivel son bastante sencillas. El siguiente cuadro de códi-go muestra el constructor de la clase, encargado de leer desde un archivo de texto

el contenido de cada celda y generar la primer celda de comida en una posición ale-atoria. El tamaño de los niveles es fijo. Para observar otros detalles y el resto de lasfunciones de la clase, puede consultarse el código completo del juego.

Nivel::Nivel(const string &archivoNivel) {  // abre el archivo y comprueba la correcta apertura

ifstream entrada(archivoNivel.c_str());  if(!entrada){

cout<<"ERROR: No se encontro el archivo "<<archivoNivel<<endl;exit(-1);

// lee el nivel desde el archivo a la matriz  for(int i=0; i<37; i++){  for(int j=0; j<50; j++){

entrada>>nivel[i][j];}

}entrada.close();

 // genera la comidaGenerarNuevaComida();

}

Introducción al desarrollo de videojuegos con SFML

Pág 5 de 12

Page 7: POO 2011 Introduccion Al Desarrollo de Videojuegos

5/17/2018 POO 2011 Introduccion Al Desarrollo de Videojuegos - slidepdf.com

http://slidepdf.com/reader/full/poo-2011-introduccion-al-desarrollo-de-videojuegos 7/12

 

En esta sección se explicarán algunos conceptos y técnicas utilizadas en el desa-rrollo de videojuegos en general y se mostrará como completar la implementacióndel videojuego diseñado anteriormente utilizando la biblioteca SFML (Simple and Fast Multimedia Library)

SFML ( www.sfml-dev.org

 

 ) es una biblioteca orientada al desarrollo de videojuegosque provee acceso a dispositivos gráficos, de sonido, de entrada y muchas otrasutilidades. Una de sus principales ventajas es ser orientada a objetos, lo cual hacemás sencilla su utilización y nos permite aplicar muchos conceptos abordados du-rante el cursado de la materia. Además, se encuentra disponible para múltiples pla-taformas y diversos lenguajes de programación y provee muchas funcionalidadesde alto nivel que resultan útiles a la hora de crear videojuegos. La biblioteca es soft- ware libre y se encuentra en desarrollo continuo, consolidándose como una de lasmás utilizadas.

El ciclo de vida de un videojuego genérico puede observarse en la Figura 5. En laetapa de inicialización se crea la ventana de juego y se cargan todos los recursos

necesarios (imágenes, sonidos, etc.). También se inicializan, de ser necesario, ob- jetos que intervengan en la lógica del juego.Luego de la inicialización, el juego entra en un bucle que repite tres conjuntos prin-cipales de acciones: el manejo de eventos, la actualización y el redibujado.El primer paso de una iteración es el procesamiento de los eventos, la mayoría delos cuales corresponden a la entrada por parte del usuario del usuario. Algunosejemplo de estos son presionar teclas, soltarlas o mover el ratón.En la etapa de actualización se modifica el estado del juego en base a la entradadel usuario adquirida en la etapa anterior y otras variables referentes al juego, porejemplo la colisión con una celda con comida, la adquisición de determinado item ola colisión con un enemigo. En la gran mayoría de los casos el estado del juego esactualizado teniendo en cuenta el tiempo transcurrido, esto es muy importante ya

que permite que un juego se actualice siempre a la misma velocidad sin importar lapotencia de la máquina en la que esté ejecutándose.La última etapa consiste en redibujar en la pantalla los objetos objetos que confor-man el juego.La cantidad de veces por segundo que la imagen del juego se actualiza (y por endela cantidad de veces que el bucle se ejecuta) se conoce como tasa de frames porsegundo o FPS, este valor es utilizado generalmente como una medida de la perfor-mance del juego ya que cuanto mayor sean los FPS, más fluido se visualizará el juego.En los párrafos siguientes se explicará con mayor detalle la implementación cadauna de las etapas mencionadas.

Pág 6 de 12

Page 8: POO 2011 Introduccion Al Desarrollo de Videojuegos

5/17/2018 POO 2011 Introduccion Al Desarrollo de Videojuegos - slidepdf.com

http://slidepdf.com/reader/full/poo-2011-introduccion-al-desarrollo-de-videojuegos 8/12

 

Figura 5. Ciclo de vida de un videojuego.

En el recuadro de código siguiente se observa la declaración de la clase que repre-senta al juego. La clase posee como atributos punteros al objeto víbora, al nivel y auna ventana, a la cual se le pedirá la entrada del usuario y sobre la cual se dibujaráel juego. También posee como atributos las imágenes que serán utilizadas en la re-presentación del juego. El constructor se encargará de la inicialización de estos

componentes, mientras que la función Correr() realizará el bucle principal del juegollamando a las tres funciones privadas que se corresponden con las etapas mencio-nadas anteriormente.

class Juego {  private:

Vibora *miVibora;Nivel *miNivel;sf::RenderWindow *ventana;sf::Image imgPared, imgPoo, imgVibora;

 void ProcesarEventos();

  void ActualizarEstado();  void Dibujar(); 

public:Juego();~Juego();

  void Correr();};

El código correspondiente al constructor de la clase  Juego se muestra debajo, elmismo se encarga de la inicialización de la ventana creando un nuevo objeto de tiposf::RenderWindow al cual se le especifica el tamaño deseado mediante un objetode tipo sf::VideoMode y el título de la ventana. Al inicializar el objeto apuntado por elpuntero ventana, SFML crea automáticamente la ventana de dibujo. El constructortambién se encarga de cargar las imágenes que serán utilizadas para dibujar el jue-go, explicaremos su utilización más adelante.

Pág 7 de 12

Page 9: POO 2011 Introduccion Al Desarrollo de Videojuegos

5/17/2018 POO 2011 Introduccion Al Desarrollo de Videojuegos - slidepdf.com

http://slidepdf.com/reader/full/poo-2011-introduccion-al-desarrollo-de-videojuegos 9/12

 

Juego::Juego(){// crea la ventana del juegoventana=new sf::RenderWindow(sf::VideoMode( 600,400),"POO Snake");// carga las imagenesimgPared.LoadFromFile("pared.png");imgPoo.LoadFromFile("poo.png");

imgVibora.LoadFromFile("vibora.png");  // inicializa la vibora y el nivelmiNivel=new Nivel("nivel.niv");miVibora=new Vibora(miNivel);

}

En este punto, es conveniente destacar que todas las clases de la biblioteca SFMLse encuentran dentro del espacio de nombressf , por lo cual es necesario anteponerel prefijo sf:: al nombre de cada clase correspondiente a la biblioteca o colocar lasentencia using namespace sf; al principio de cada archivo en el que se utilice al-gún componente de SFML. En este caso hemos preferido la primer alternativa paraque a simple vista resulte más fácil identificar cuáles clases son las que pertenecena la biblioteca.

A la hora de dibujar sobre la ventana, debe tenerse en cuenta el sistema de coorde-nadas utilizado por la misma. El origen de coordenadas se encontrará en la esquinasuperior izquierda de la ventana, y la posición de cualquier punto estará medida enfunción de la distancia positiva a este origen. Los máximos valores de las coordena-das estarán limitados por las dimensiones de la ventana especificadas en el mo-mento de su creación. En la Figura 6 puede observarse la ventana de juego y variospuntos representados sobre la misma.

Figura 6. Sistema de coordenadas de la ventana de juego.

Para procesar los eventos SFML utiliza una técnica conocida como  polling, estaconsiste en consultar a la ventana en cada iteración del juego por los eventos ocu-rridos. Para esto, los eventos ocurridos son almacenados en una cola de la cual esnecesario ir extrayéndolos uno a uno y realizar las acciones pertinentes si coincidencon el tipo de evento buscado.En el recuadro de código que sigue se observa la implementación de la funciónProcesarEventos(). La función GetEvent(...) quita un evento de la cola y lo colocaen la variable e que es de tipo sf::Event , un tipo definido especialmente para repre-sentar eventos. Además, la función devuelve verdadero cuando efectivamente pudodesencolarse un evento o falso si la cola de eventos está vacía. De esta manera, elbucle while se encarga de quitar uno a uno los eventos de la cola. Para cada eventoprimero se debe averiguar si es del tipo que nos interesa, ya que puede haber

Pág 8 de 12

Page 10: POO 2011 Introduccion Al Desarrollo de Videojuegos

5/17/2018 POO 2011 Introduccion Al Desarrollo de Videojuegos - slidepdf.com

http://slidepdf.com/reader/full/poo-2011-introduccion-al-desarrollo-de-videojuegos 10/12

 

eventos de diversos tipos (por ejemplo, una tecla presionada, una tecla soltada, unmovimiento del ratón, etc). En este caso, los eventos que nos interesan manejarson las teclas presionadas, por lo que se compara el campo Type del evento conuna constante que representa al tipo buscado (tecla presionada). Una vez se cono-ce que el evento es efectivamente la pulsación de una tecla, resta averiguar cuál esdicha tecla. Para esto se realiza nuevamente una comparación entre un campo delevento que indica el código de la tecla correspondiente y constantes de SFML querepresentan las teclas deseadas. En función de la tecla que haya sido presionada,se cambia la dirección de la víbora. Para mayores detalles sobre el manejo deeventos en SFML puede consultarse el tutorial: http://www.sfml-dev.org/tutorials/1.6/window-events.php.

void Juego::ProcesarEventos(){sf::Event e;

  // mientras queden eventos en la cola,// sacamos el proximo evento

  while(ventana->GetEvent(e)) {  // pregunta si el evento es una presion de tecla 

if(e.Type == e.KeyPressed){  // pregunta cual es la tecla y mueve la vibora  switch(e.Key.Code){  case sf::Key::A:

miVibora->CambiarDireccion(Vibora::IZQUIERDA);  break; 

case sf::Key::S:miVibora->CambiarDireccion(Vibora::ABAJO);

  break; 

case sf::Key::D:miVibora->CambiarDireccion(Vibora::DERECHA);

  break; 

case sf::Key::W:miVibora->CambiarDireccion(Vibora::ARRIBA);

  break;

}}

}}

Como se dijo anteriormente, para actualizar el estado del juego es necesario teneren cuenta el tiempo transcurrido entre las sucesivas actualizaciones para que el juego funcione a la misma velocidad en cualquier computadora. Para conocer estevalor, puede utilizarse la función GetFrameTime() de la clase sf::RenderWindow .Esta función devuelve un real con la cantidad de segundos transcurridos desde laúltima actualización de la ventana. Puede utilizarse el valor devuelto por esta fun-ción para mover a la víbora solo cuando haya pasado un determinado lapso de

tiempo.En el recuadro de código siguiente se muestra el código de la función encargada deactualizar el estado del juego. La variable tiempoAcumulado permite acumular eltiempo transcurrido en cada actualización para poder conocer el momento en el quedebe moverse la víbora. La variable es declarada como estática para que no sedestruya al terminar la función y conserve su valor entre llamada y llamada, se hu-biera podido lograr el mismo comportamiento declarándola como atributo de la cla-se. En cada actualización el tiempo transcurrido es adicionado a dicha variable ycuando se cumple un lapso de 0.2 segundos, es tiempo de mover a la víbora y vol-ver hacia atrás el acumulador de tiempo. La dirección de movimiento de la víbora yahabrá sido ajustada en la funciónProcesarEventos().

Pág 9 de 12

Page 11: POO 2011 Introduccion Al Desarrollo de Videojuegos

5/17/2018 POO 2011 Introduccion Al Desarrollo de Videojuegos - slidepdf.com

http://slidepdf.com/reader/full/poo-2011-introduccion-al-desarrollo-de-videojuegos 11/12

 

void Juego::ActualizarEstado(){// un acumulador de tiempo para saber cuando mover

  static float tiempoAcumulado=0;  // actualizamos el acumulador con el tiempo

// transcurrido desde la ultima actualizacióntiempoAcumulado+=ventana->GetFrameTime();

  // reseteamos el acumulador cada 0.2 segundos// y movemos la vibora

  if(tiempoAcumulado>=0.2){tiempoAcumulado-=0.2;miVibora->Mover();

}}

Para la representación gráfica de los elementos del juego, SFML nos provee de lasclases sf::Image y sf::Sprite.La primera de estas clase sirve para representar imágenes. Una imágen es un arre-glo bidimensional de píxeles, un píxel es el elemento mínimo en que puede separa-se una imagen, es un punto que tiene un único color. Las imágenes son recursosque ocupan generalmente bastante memoria y son costosos de manipular.Por otro lado, un sprite es un objeto que tiene una representación gráfica dada poruna imagen, pero posee además otras propiedades que definen completamente surepresentación, por ejemplo su posición en la pantalla, su tamaño, su rotación, etc.A diferencia de las imágenes, los sprites son livianos ya que no almacenan grandesvolúmenes de datos, sino únicamente propiedades sobre la representación de laimagen a la que están asociados.La distinción entre imagen y sprite es muy importante, las imágenes son cargadasuna única vez desde el disco y rara vez son modificadas, mientras que las propie-dades de los sprites varían continuamente. SFML no permite dibujar una imagen enpantalla ya que muchas de sus propiedades no están definidas (por ejemplo su po-sición o tamaño). Por otro lado, si posee funciones para dibujar un sprite (que debeestar previamente asociado a alguna imagen).

En siguiente fragmento de código se observa la función Dibujar() de la clase Juego.El proceso de redibujado consiste básicamente en tres pasos. Primero debe borrar-se todo el contenido de la ventana, en este caso, pintándola de color negro. Esto selogra llamando a la función miembro Clear(...) de la clase ventana especificando elcolor mediante un objeto de tipo sf::Color .En segundo lugar debe realizarse el dibujado de los objetos mediante sprites. En elcaso del nivel se recorre cada celda y se pregunta por su contenido, en caso de noestar vacía, se la dibuja utilizando un sprite al que se le asigna una imagen corres-pondiente a dicho contenido (pared o comida) y se lo posiciona en la pantalla te-niendo en cuenta su ubicación en la matriz y el tamaño de la imagen (recordar elsistema de coordenadas utilizado por la ventana). Para el dibujado del sprite se utili-

za la función miembro Draw(...) de la clase sf::RenderWindow . El proceso de repre-sentar al nivel mediante una matriz de imágenes más pequeñas se conoce general-mente como tiled rendering o tile map.El dibujado de la víbora es muy similar al realizado con el nivel, pero utilizando unaúnica imagen.El tercer y último paso del redibujado es hacer efectivos los cambios en la ventanallamando a la función Display() para que la misma sea actualizada.En el recuadro de código siguiente se muestra la implementación de la funciónDi-bujar() de la clase Juego.

void Juego::Dibujar(){// limpia la ventana

Pág 10 de 12

Page 12: POO 2011 Introduccion Al Desarrollo de Videojuegos

5/17/2018 POO 2011 Introduccion Al Desarrollo de Videojuegos - slidepdf.com

http://slidepdf.com/reader/full/poo-2011-introduccion-al-desarrollo-de-videojuegos 12/12

 

ventana->Clear(sf::Color(0,0,0,255));  // crea el sprite para dibujar el nivel y la vibora

sf::Sprite s; 

// recorre las celdas del nivelfor(int i=0; i<37; i++){

  for(int j=0; j<50; j++){// pregunta por el contenido de la celda

  int contenidoCelda=miNivel->QueHayEnCelda(Coord2i(j, i));  // en caso de no estar vacia, posiciona el sprite,

// le asigna la imagen correspondiente y la dibuja  if(contenidoCelda!=0){

s.SetPosition(j*imgPared.GetWidth(), i*imgPared.GetHeight());  if(contenidoCelda==1) s.SetImage(imgPared);  if(contenidoCelda==2) s.SetImage(imgPoo);

ventana->Draw(s);}

}}

 // asigna al sprite la imagen para las celdas del cuerpo de la viboras.SetImage(imgVibora);Coord2i celda(0,0);

  // recorre las celdas de la vibora, posiciona y dibuja cada celda

  for(int i=0; i<miVibora->Largo(); i++){  celda=miVibora->GetCelda(i);  s.SetPosition(celda.x*imgVibora.GetWidth(), celda.y*imgVibora.GetHeight());  ventana->Draw(s);

// actualiza la ventanaventana->Display();

}

Hemos analizado el desarrollo completo de un pequeño videojuego, tanto del dise-ño de su lógica como los aspectos específicos correspondientes a un videojuego.Para apreciar los detalles restantes puede analizarse el código completo del ejem-plo. Asímismo, se recomienda recurrir a la documentación de la biblioteca SFML

para una referencia completa de las clases y funcionalidades provistas por la biblio-teca, y a los tutoriales para una introducción a la utilización básica de los principalescomponentes de la misma la misma.El paquete con las cabeceras y binarios de la biblioteca para ZinjaI, así como eltemplate de proyecto para videojuegos que la utilicen, pueden encontrarse en lasección descargas de la página de ZinjaI.

Diseño del videojuego Snake

• Documentación de SFML: www.sfml-dev.org/documentation/1.6/• Tutoriales de SFML: www.sfml-dev.org/tutorials/1.6/ • Paquete SFML para Zinjai: http://zinjai.sourceforge.net/

Pág 11 de 12