Jesús Bosch

XNA, programación gráfica y desarrollo de videojuegos por un Microsoft Student Partner

February 2010 - Artículos

[XNA] Implementando un clon de Tetris con XNA

El Tetris es un must-do para cualquier programador que se precie... pues con esto he podido poner un check en la lista de "cosas que hacer para ser un buen programador". Un juego, por sencillo que sea -como es el caso del tetris- contiene mucha lógica, y si no se estructura bien la complejidad puede crecer de forma exponencial... llegando a complicar de tal forma la codificación que resulte imposible continuar con el desarrollo del juego. El caso es que si te animas a implementar este pequeño juego, te darás cuenta de la importancia de diseñar antes de picar código -algo a lo que estamos relativamente acostumbrado cuando programamos aplicaciones de gestión-. En este caso he usado una herramienta de diseño increiblemente avanzada... EL EXCEL. Pues sí... el excel ¿qué pasa...? Lo cierto es que me ha ido perfecto para "debugar mentalmente" algunas situaciones, así como tener controlada la forma y tamaño de cada uno de los tipos de piezas disponibles en un tetris que se precie. Como demuestra la captura de pantalla:

El resultado de unas horillas de codificación es el siguiente:

Dicho esto... vamos a ver un poco el algoritmo de implementación (a grandes rasgos):

 1 Crear pieza aleatoria               
 2 Leer nueva posición               
 3 Comprobar si la nueva posición está libre               
     3.1 Si NO está libre copiar a Matriz              
     3.2 Si está libre, lo movemos a la posición solicitada              
4 Comprobar si hay línea en la matriz               
    4.1 Si hay línea, desplazar todo una línea hacia abajo a partir de esta, sobreescribiendo              

¿Fácil verdad?  Toda la lógica se encuentra en las clases Tablero y Ficha, que muestro en este diagrama de Visual Studio:

Los objetos importantes son MatrizGlobal, que es una matriz de dos dimensiones donde se van almacenando todas las piezas que no están bajo el control del jugador, y sobre la cual detectaremos colisiones con la ficha que sí mueve el usuario, si ha llegado al tope (game over), si hay línea, etc.

public Color?[,] MatrizGlobal;

Por defecto todos los valores de la matriz serán null, y a medida que el usuario vaya soltando piezas sobre el "suelo" de la matriz, estas piezas pasarán a formar parte de la matriz en forma de Color (para posteriormente ser capaces de pintar cada pieza con la textura que toca).

La clase update de Tablero ejecuta el algoritmo que he mostrado antes:

public void Update(GameTime gameTime)
{
  
if (tipoMovimiento != Ficha.TipoMovimiento.gameOver)
   {

     
// Lógica de la ficha
     
tipoMovimiento = this.Ficha.Update(gameTime, ref MatrizGlobal);

      // Comprobar si hay lnea
     
if (tipoMovimiento == Ficha.TipoMovimiento.colisionVertical)
      {
        
this.ComprobarLineas();
        
this.Ficha = new Ficha();
      }
   }
  
else
  
{
     
// Si pulsa espacio, limpiamos tablero y reiniciamos
     
if (Keyboard.GetState().IsKeyDown(Keys.Space))
      {
        
this.ResetGame();
      }
   }
}

En la clase Ficha tenemos como método más "complicado" el que calcula si se puede mover la pieza a la nueva posición solicitada (la pieza siempre cae hacia abajo, más si el jugador la está haciendo rotar o mover hacia derecha o izquierda). Sería esta la implementación del método:

int anchoBloque = this.ancho[this.rotacionActual];
int altoBloque = this.alto[this.rotacionActual];

int anchoTablero = MatrizGlobal.GetLength(0);
int altoTablero = MatrizGlobal.GetLength(1);

// Comprobamos posicin de la pieza con el tablero
for (int y = 0; y < altoBloque; y++)
{
  
for (int x = 0; x < anchoBloque; x++)
   {
     
if (this.Espacio[rotaciontmp, x, y] == true)
      {
        
if(nuevaPosicionY + y == altoTablero)
           
return TipoMovimiento.colisionVertical;
        
if(nuevaPosicionX + x >= anchoTablero)
           
return TipoMovimiento.fueraLimites;
        
if (MatrizGlobal[nuevaPosicionX + x, nuevaPosicionY + y] != null)
           
return TipoMovimiento.colisionLateral;

         if (this.PosicionY + y + 1 < altoTablero && MatrizGlobal[nuevaPosicionX + x, this.PosicionY + y + 1] != null)
           
return TipoMovimiento.colisionVertical;
      }
   }
}

return TipoMovimiento.correcto;

¿Lo próximo? Creo que va a ser divertido implementar una IA que juegue sola al tetris... (y digo sola porqué ningún humano es capaz de vencer una máquina jugando al tetris...)

Posted: 27/2/2010 13:08 por Jesús Bosch | con 16 comment(s) |
Archivado en:
[webcast] XNA Avanzado: "Cómo se hizo: Kaotik Puzzle"

En este webcast conoceremos de la mano del autor del videojuego "Kaotik Puzzle", Silvino Esquiva, el caso de éxito de la producción de un videojuego Indie, y su comercialización en XBOX Live. Silvino nos enseñará la arquitectura utilizada, las líneas generales del desarrollo, y sobretodo el motor de IA, punto donde destaca especialmente este entretenido videojuego.

Silvino Esquiva es un experimentado Modelador 3D, que además demuestra en esta producción tener ámplios conocimientos de desarrollo en XNA. Ha trabajado durante años como profesor en escuelas de 3D y en distintos tipos de proyectos de modelado.

Registro:
http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032443443&EventCategory=4&culture=es-ES&CountryCode=ES

Posted: 17/2/2010 8:15 por Jesús Bosch | con 1 comment(s)
Archivado en: ,,,
[OT] Un poco de marujeo...: Windows Phone 7 y XBOX Live

Hoy tiraré la casa por la ventana... y me sumaré a los marujeos múltiples que han surgido a partir de la presentación del nuevo Windows Phone ayer mismo en el Mobile World Congress, por parte del propio Steve Ballmer en Barcelona. Desde el punto de vista del desarrollo de videojuegos, destaca la incorporación de XBOX Live en los teléfonos móbiles, y aunque no se ha explicitado totalmente, se ha dejado entrever que soportará la ejecución de potentes videojuegos, al nivel de videoconsolas como PSP. De ello habla Vodoo Extreme, en su resumen de nuevas características.

Algunos rumores, algunos de ellos procedententes de Microsoft, parecen indicar que además de XNA el nuevo Windows Phone podría soportar Silverlight.

Seguramente saldremos de dudas en el próximo gran evento organizado por Microsoft: el MIX en Las Vegas, el próximo mes de marzo, donde ya se pueden entrever numerosas charlas de desarrollo de videojuegos para dispositivos móbiles (aunque no se detalla mucho más...).

[IA] Búsquedas en grafos en C#

La teoría de grafos es un campo muy ámplio, que daría contenido para escribir no un post, sinó varios libros! Pero aquí os enseño algunos expermientos que he hecho para su aplicación en programación de videojuegos. En un juego estilo Command & Conquer se podría usar un grafo para saber si el jugador tiene permitido contruir la unidad "soldado". Como recordaréis, este juego permite construir unidades si antes cumples determinados requisitos, como haber construido el edificio "barracones", como muestra el siguiente diagrama:

Podríamos implementar esto a base de numerosas sentencias "If" anidadas, pero el código sería muy difícil de mantener y propenso a bugs: malo. Así pues, se podrían usar técnicas de búsqueda de grafos para ver qué unidades o edificios podemos construir. Otra opción es para la planificación de rutas (con su culminación en el algoritmo A* Pathfinding), es decir, determinar si un objeto puede moverse de una zona a otra del juego.

Existen varios algoritmos de búsqueda dentro de un grafo... aquí os muestro una implementación muy sencilla. Pero antes veamos de forma muy resumida los componentes de un grafo. En este algoritmo, el grafo consta de Nodos y de Lados. Los Nodos son las circunferéncias de la imágen, y son los puntos por los cuales nos queremos mover. Los lados son conexiones entre dos puntos. Así pues entre el Nodo 1 y el Nodo 6 existiría un Lado que va a contener la información de los nodos que une (1-6).

Estos objetos pueden ser definidos conecptualmente mediante clases del siguiente modo:

Estas clases sólo definen el grafo y sus nodos, de la búsqueda podrían encargarse clases específicas, con sus algoritmos determinados. En este caso he utilado la siguiente, basada en el algoritmo "Deep First Search". Este algoitmo va a encontrar la ruta que busquemos, pero sin tener en cuenta si es o no la más eficiente. El concepto eficiente podría variar dependiendo de los requerimientos, podría ser el número de nodos intermedios, o el número de nodos intermedios teniendo en cuenta el "peso" de cada lado (un lado puede cruzar una montaña, y el movimiento en esa zona sería más lento y costoso). En este caso la implementación es la siguiente:

La implementación del algoritmo es la siguiente:

 public void BuscarRuta()

   
// Limpiamos
  
nodosVisitados.Clear();
   ruta.Clear();

  
// stack de referencias a los lados (cola LIFO)
  
Stack<GrafoLado> cola = new Stack<GrafoLado>();

  
// Se crea un lado tonto y se pone en el stack
  
GrafoLado ladoDummy = new GrafoLado(this.origen, this.origen, 0f);
 
   cola.Push(ladoDummy);

  
// Mientras haya lados en el stack, seguimos buscando
  
while
  
(cola.Count > 0)
   {
     
GrafoLado ladoSiguiente = cola.Pop();

     
// Guardamos en la ruta
     
ruta.Add(ladoSiguiente.To);

     
// Guardamos registro de nodos visitados
     
nodosVisitados.Add(ladoSiguiente.From);

     
// Si el siguiente lado es el de destino,
     
// hemos encontrado la ruta
     
if(ladoSiguiente.To == destino)
      {
        
this.rutaEncontrada = true;

        
return;
      }

foreach (GrafoLado lado in grafo.Lados)
{
   
// Si el nodo no existe en la lista de visiados, y adems es accesible desde el nodo actual,
  
// lo aadimos al stack
  
uint visitado = nodosVisitados.Find(b => b == lado.To );

     
if(visitado == 0 && lado.From == ruta[ruta.Count-1])
      {
         cola.Push(lado);

        
break;
      }
   }
}

// No se ha encontrado ruta...
this.rutaEncontrada = false;

El código como siempre lo encontraréis adjunto en el interior del artículo.

Posted: 13/2/2010 13:20 por Jesús Bosch | con 7 comment(s)
Archivado en: ,
[eventos] Charla presencial de XNA en la Universitat de Lleida

El próximo 11 de febrero celebramos en la Universitat de Lleida el Microsoft Break Lleida. Habrá varias charlas por parte de ponentes variopintos. Como no podía ser de otra forma en cualquier evento universitario... va a haber una charla de XNA, que dará un servidor. Va a ser una charla introductoria, en la que presentaré el framework, sus posibilidades en distintos dispositivos, las posibilidades de distribución en el Marketpace de XBOX Live, así como varios ejemplos en 2D y 3D. Espero veros por allí! :-D


Para apuntaros al evento podéis hacerlo en el siguiente enlace:
http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032442212&Culture=es-ES