Jesús Bosch

XNA y desarrollo de videojuegos por un Microsoft Student Partner
[MIX] Herramientas de desarrollo para windows phone 7 ya disponibles!

Lo acaba de anunciar Scott Guthrie en el MIX2010... ya podemos descargar las herramientas de desarrollo para Phone 7!! Estas herramientas se basan en desarrollo Silverlight y XNA. Podéis descargarlas en http://developer.windowsphone.com/windows-phone-7-series/ La descarga de Visual Studio 2010 Express for Windows Phone (uf) es gratuita.

Todo esto en riguroso directo desde Las Vegas.. :-) enjoy!



[OT] XNA Game Studio 4.0: Nos vemos en Las Vegas!

Desde hace unos días ya es oficial... XNA Game Studio 4.0 será un poco más portable... esta vez sobre Windows Phone 7! Y además con todo su esplendor... portabilidad "total", juegos 3D, XBOX Live, etc. El caso es que se ha estado hablando de ello en el GDC, y puede encontrarse información de ello en los blogs oficiales, como el de Michael Klucher. Otro tema interesante es que soporta la integración con Visual Studio 2010.

El caso es que en el MIX 2010 se van a mostrar más detalles al respecto, en sesiones específicas de desarrollo de XNA 4 sobre la plataforma windows Phone. Allí voy a estar, y os lo iré narrando a diario! :-)

[XNA] Introducción al trazado de rayos con XNA

Los rayos son usados en desarrollo de videojuegos para trazar líneas imaginarias entre un punto y otro en el espacio tridimensional, y valorar si hay intersecciones entre el vector que une ambos. Puede servir para detectar si un disparo intersecciona con su objetivo o no, y para calcular la distancia entre este y quien ha disparado... o también puede ser útil para pintar un texto encima de un modelo en el espacio 3D... o para hacer un Drag & Drop de modelos en un espacio tridimensional. De hecho, el trazado de rayos puede ser utilizado incluso para renderizar escenas... pero no se usa en videojuegos a tiempo real porque consume muchos recursos.

Con un poco de álgebra se puede calcular la intersección entre un rayo y una esfera, entre un rayo y un plano, un cubo, o incluso un triángulo... las matemáticas para hacer estos cálculos pueden llegar a ser más o menos complicadas... pero si programas en XNA, se te va a caer la lagrimita de lo fácil que es utilizar técnicas de trazado de rayos. A pesar de esta ventaja, hay que decir que la documentación en MSDN acerca de la estructura Ray es escueta... por decirlo de forma amable. Así que voy a compartir con vosotros algunos experimentos que he hecho con ella y os puede interesar conocer.

En este ejemplo lo que hacemos es crear un rayo a partir de la posición del puntero del ratón sobre la pantalla, y calcular el destino del rayo a partir de la vista y proyección de la camara -pero creas que es gran cosa, porqué aquí XNA vuelve a socorrernos-.

Así pues, en el método update, "refrescaremos" el rayo llamando al método siguiente:

   1: private Ray posicionarRayo() 
   2:         {
   3:             Vector2 posicionMouse = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);
   4:  
   5:             // Calculamos a qué posiciones del World corresponden las del mouse con Unproject
   6:             Vector3 puntoCercano = GraphicsDevice.Viewport.Unproject(new Vector3(posicionMouse, 0f),
   7:                 camara.projection, camara.view, Matrix.Identity);
   8:  
   9:             Vector3 puntoLejano = GraphicsDevice.Viewport.Unproject(new Vector3(posicionMouse, 1f),
  10:                 camara.projection, camara.view, Matrix.Identity);
  11:  
  12:  
  13:             Vector3 direccion = puntoLejano - puntoCercano;
  14:  
  15:             direccion.Normalize();
  16:  
  17:             return new Ray(puntoCercano, direccion);
  18:         }

El método realmente interesante de este código es Unproject. Lo que hace es proyectar el un vector a partir de la posición del mouse, en una posición de la escena en 3D.

Después, para saber si hay intersección entre el rayo y el BoundingSphere, sería algo tan sencillo como utilizar un método de la propia estructura Ray:

   1: rayo.Intersects(ref esfera, out distancia);

Donde esfera es un boundingSphere y la distancia es la longitud a la que existe la intersección entre el rayo y el boundingsphere.

Finalmente, para pintar el texto encima del modelo 3D (en este caso las primitivas de un BoundingSphere), tenemos que traducir la posición en el world del modelo (en este caso hemos puesto Matrix.Identity) a lo que es la pantalla:

   1: string mensaje = "Rayo intersecciona con la esfera!";
   2:                 
   3: // Calculamos la posición en pantalla del boundingSphere gracias al método Project del Viewport
   4: Vector3 posicionenPantalla = graphics.GraphicsDevice.Viewport.Project(
   5: Vector3.Zero, camara.projection, camara.view, Matrix.Identity);
   6:  
   7: // Obtenemos el centro del texto
   8: Vector2 centroTexto = this.fuente.MeasureString(mensaje) / 2;
   9:  
  10: Vector2 posicionTexto = new Vector2(posicionenPantalla.X, posicionenPantalla.Y - (esfera.Radius + 50));
  11:  
  12: spriteBatch.DrawString(fuente, mensaje, posicionTexto - centroTexto, Color.White);

El resultado de este ejemplo sencillo sería el siguiente, donde estamos pintando un boundingsphere (aparece rojo si ponemos el mouse “sobre él”, y blanco si el mouse queda “fuera” de él, además aparece el texto en blanco por encima):

Además, en XNA Creators Club Online hay un par de ejemplos interesantes relacionados con el trazado de rayos donde podrás ampliar conocimientos:

Rayos con modelos
http://creators.xna.com/en-US/sample/picking

Rayos a nivel de triangulos
http://creators.xna.com/en-US/sample/pickingtriangle

Posted: 8/3/2010 10:10 por Jesús Bosch | con 1 comment(s)
Archivado en: ,
[XNA] Aprende a programar C# con XNA

XNA Game Studio se está convirtiendo cada vez más en una plataforma para introducir el mundo de la programación en C# a los estudiantes. Este libro gratuito no da por supuesto ningún conocimiento previo de programación. No solo se aprende C# sinó que es una perfecta introducción, muy básica, al desarrollo de videojuegos. Sin duda una lectura muy interesante para jóvenes programadores.



Podéis descargar el libro en PDF aquí:

http://www.lulu.com/product/download/a-simple-introduction-to-game-programming-with-c%23-and-xna-31/5438606

También existe una versión online en esta URL:

http://xnagamemaking.com/

Posted: 4/3/2010 13:19 por Jesús Bosch | con 2 comment(s)
Archivado en:
[XNA] Game Engines para XNA

Hoy os presento una recopilación de Game Engines para XNA. Como sabéis, la plataforma XNA ofrece facilidades para el renderizado de gráficos, carga de contenidos y demás, pero en videojuegos completos es necesaria la utilización de un engine que extienda y facilite estas funcionalidades, y añada otras, como pueden ser los motores de física o animación de modelos 3D. Cualquier engine importante que detectéis que falta en la lista me lo decís y lo añado ipso facto :-)

Tomahawk XNA Game Engine


Completo framework open source compatible con XNA 3.1 para XBOX 360 y Windows. Internamente se basa en otros engines para la física y animaciones, lo que lo hacen muy potente y desacoplado. Uno de los problemas que le veo es la documentación del proyecto.

http://www.assembla.com/wiki/show/tomahawkengine/

 CAROT Engine


Todavía en versión Alpha, y orientado a 2D, parece tener como punto fuerte un foro bastante activo, lo cual es una garantía para la continuidad del proyecto. Para proyectos basados en Windows usa un wrapper de las librerías de sonido Audiere, en C++. La descarga es gratuita.

http://carotengine.com/

Ox Game Engine for XNA


Open Source. Se autodefine como un engine ya maduro para proyectos 3D, incluye un editor de escenas 3D visual, facilidad en renderizado de GUI en 2D, también con un editor visual, física basada en JigLibX, animaciones, y un sistema de scripting basado en C#.  

http://oxgameengine.codeplex.com/

QuickStart Engine
Engine 3D, open source. Se autodefine como potente y fácil de usar. Además puedo deciros que lo he probado, y es realmente sencillo de utilizar, además de tener una comunidad que atiende a las peticiones de mejoras, si van en beneficio de todos. Permite gestionar física, animaciones, renderizado, etc.

http://www.codeplex.com/QuickStartEngine

JigLibX Physics Engine

Excelente motor de física Open Source. Es un port a XNA del proyecto JigLib.

http://www.codeplex.com/JigLibX


Klib Engine (2D)
Engine open source para juegos 2D basados en XBOX 360 y Windows. Este framework quiere facilitar operaciones comunes como físicas, escenas, partículas, efectos de post-procesado, gestión del input y más.

http://klibenginexna.codeplex.com/


DEngine - C# XNA 2D Game Engine
Engine 2D gratuito que se basa en la lectura de XML para la gestión de niveles, facilita la animación de sprites, física basada en FarseerPhysics, editor de niveles, controles GUI, algoritmo A*, y un ejemplo de videojuego RTS basado en este engine.

http://dengine.codeplex.com/


Phoenix XNA Engine
Un engine gratuito todavía en desarrollo pero bastante prometedor, ya que su desarrollo se basa en una comunidad bastante activa. Tiene funcionalidades como generación de terrenos a partir de texturas, gestión de Input, texturas, cámaras, Networking, etc. 

http://phoenixxna.codeplex.com/


XEN Graphics API for XNA
xen
Engine 3D que se esfuerza en ser fácil de utilizar y a su vez ofrecer un alto rendimiento. Muy interesante es el hecho de su completa documentación y tutoriales que demuestran la facilidad de uso.

http://xen.codeplex.com/


SilverSprite
No se podría definir exactamente como un engine XNA… pero es interesante mencionarlo. Permite ejecutar juegos 2D basados en XNA en Silverlight, en sus versiones 2 y 3. 

http://silversprite.codeplex.com/


Garage Games Torque X

Engine comercial para el desarrollo de  videojuegos para varias plataformas. Tiene muchos años de historia y es bastante famoso. Tienen un framework tan trabajado que programar bajo esta plataforma se parece poco a desarrollar en XNA (para lo bueno y para lo malo que ello conlleva). Tiene editores de niveles 2D y 3D y un montón de utilidades más.

http://www.torquepowered.com/

Mercury particle engine
Open source. Motor de partículas para Windows PC y XBOX 360.

http://www.codeplex.com/mpe


SubBurn
Comercial. Engine gráfico para 3D focalizado en iluminación y el renderizado.

http://www.synapsegaming.com/products/sunburn/


bEpUphysics
Otra librería gratuíta (siempre que no se use para obtener beneficios económicos) de físicas para XNA. Contiene documentación y algunos tutoriales.

http://www.bepu-games.com/BEPUphysics/downloads.htm

Posted: 3/3/2010 8:57 por Jesús Bosch | con 6 comment(s)
Archivado en: ,,,
[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

[IA] Wall Avoidance: Steering Behaviors en XNA (III de II)

Sí... esta es la parte 3 de 2... y es que en la anterior escribí una implementación de "obstacle avoidance", pero claro, los obstáculos eran siempre circulares. En esta nueva versión, además de circulares, los obstáculos pueden ser líneas, con lo cual se puede dibujar prácticamente cualquier forma geométrica.

Esto es lo que vamos a conseguir con esta nueva versión del ejemplo:

Os dejo el código para que juguéis con él, y si álguien se anima a mejorarlo ya sabéis. Una de estas posibles mejoras, y que seguramente no seria muy difícil, sería aplicar un smooth a las rotaciones, es decir, impedir que el agente gire como un loco...

Posted: 13/1/2010 16:20 por Jesús Bosch | con 1 comment(s) |
Archivado en: ,
[IA] Robocup... que se prepare la FIFA!

Pues sí... hoy hablaremos de futbol! Hoy he descubierto (a pesar de que hace años que existe) la Robocup, algo más que una competición a nivel mundial entre robots futbolistas. Entre sus objetivos, a parte de fomentar la educación e investigación en IA (minucias...) destacan que quieren ganar el mundial de fútbol de la FIFA participando en la competición con las reglas oficiales y jugando como un equipo más contra otros equipos humanos. Este objetivo se lo han marcado para el año 2050... Viendo la web parece que les queda bastante trabajo por hacer, pero no van mal encaminados...

Y como no sólo de fútbol vive el hombre... también han desarrollado la competición "Robocup rescue", es decir, robots de rescate.



Cabe destacar la ayuda y documentación que ofrecen para construir un robot para la competición. Sin duda todo un mundo de posibilidades..

Posted: 9/1/2010 14:30 por Jesús Bosch | con 1 comment(s) |
Archivado en:
[IA] Obstacle Avoidance: Steering Behaviors en XNA (II de II)

En el episodio anterior hablé de algunos steering behaviors básicos. Hoy hablaré de un Steering que puede solaparse a cualquiera de los anteriores, consiguiendo efectos de IA más avanzados: el Obstacle Avoidance. La idea es que podamos aplicar este comportamiento a cualquiera de los steering behaviors que ya tenemos desarrollados, de forma que cualquiera de nuestros agentes evite las colisiones con los obstáculos existentes en el "mundo" en que se desenvuelve.

Para ello nos basaremos de nuevo en los principios de Craig Reynolds, en los que define un pseudoalgoritmo efectivo para aproximar los obstáculos mediante círculos, y evitar las colisiones con los mismos mediante la proyección de un rectángulo en frente de nuestro agente (orientado hacia la dirección de avance), que testeará en cada momento posibles intersecciones entre dicho rectángulo y los obstáculos, identificando así posibles colisiones entre el agente y estos obstáculos en un "futuro" cercano. Lo malo es que el amigo Craig no nos facilita el código... sólo nos da sus mandamientos. Para ver buenos ejemplos de código tenemos la librería OpenSteer, SharpSteer, o uno de mis libros favoritos y reciente adquisición: Programming Game AI by Example. Con todo esto y un poco de imaginación vamos a conseguir lo siguiente:

Si vísteis mi artículo anterior de steering behaviors, la diferencia está en los obstáculos con forma de circunferencia, que están repartidos por el "mundo", y que los agentes los esquivan, o nunca pasan por encima de ellos. ¿Cómo conseguimos esto? Con la librería que he desarrollado, en la clase Game solo habría que añadir lo siguiente:

bichoPursuit.behaviors.AddBehavior(new Pursuit(Arrive.Deceleration.normal, 50.0f));
bichoPursuit.behaviors.AddBehavior(new ObstacleAvoidance(ref gameWorld, 15.0f));

Lo cual quiere decir que al agente "bichoPursuit", le damos primero el behavior de pursuit, y el de obstacleAvoidance. Obviamente los círculos no se renderizarian en un juego... y serían sustitidos por los sprites 2D o modelos 3D correspondientes, aquí los uso solo para desarrollar y debugar la librería. Y con esto ya está! Bueno... lógicamente en la clase que hay por detrás he hecho un trabajo extra, implementando el nuevo steering en la clase ObstacleAvoidance:

Es muy parecida a las herederas de Steering que ya hemos visto, tiene su método "CalculateSteering". La diferencia ahora está en el uso que hace de la clase Circle para definir los obstáculos en forma de circunferencia (en una librería completa habría que definir otras formas geométricas para los obstáculos, la más flexible sería la línea). Tambien observamos un método nuevo: EnforceNonPenetrationConstraint, después veremos qué hace. La clase Circle, a pesar de ser sencilla nos va a dar mucho juego. Nunca mejor dicho :-P

CalculateSteering

Este método contiene la "chicha". Lo primero que hará será buscar todos los obstáculos próximos al agente y guardarlos en una lista. Con esto evitaremos comprobaciones excesivas con todos los obstáculos que pudieran haber en el juego, y por tanto evitaremos perder valiosísimo tiempo del procesador. Una vez tenemos identificados los obstáculos, calcularemos la distancia a partir de la cual debemos comprobar/reaccionar ante las posibles colisiones con los obstáculos circulares.

A continuación recorremos todos los obstáculos que se encuentran en el radio de acción que hemos identificado anteriormente, y dependiendo de la distancia (o incluso penetración) del agente sobre el obstáculo, generaremos una steering force proporcional hacia la dirección que se considere oportuno.

Compensación de fuerzas

El uso en paralelo de varios steering behaviors puede provocar que un steering de Flee quiera alejar al agente de su perseguidor, por ejemplo hacia la derecha, pero hacia la derecha podría estar el círculo... así pues tenemos un conflicto. Este conflicto se puede superar de varias formas... pero la más sencilla (y no necesariamente la mejor) mediante compensación de fuerzas, esto es, dando un peso específico a cada steering sobre el total, de forma que este sea tenido en cuenta para calcular el resultado final:

En la clase SteeringBehavior tendríamos esto:

if (this.HasBehavior(BehaviorType.seek))
   this._steeringForce += this._seek.CalculateSteering(entity) * this.weightSeek;

if (this.HasBehavior(BehaviorType.obstacle_avoidance))
   this._steeringForce += this._obstacleAvoidance.CalculateSteering(entity) * this.weightObstacleAvoidance;

Donde hay que destacar la multiplicación que se hace sobre la steeringForce contra su peso establecido de forma constante en este caso (pero podría ser variable según las situaciones).  Como no podemos predecir con exactitud los resultados que van a producir la compensación de fuerzas, puede darse -y se da- la situación de que un agente termine pasando por encima de un obstáculo. Para evitarlo, el behavior ObstacleAvoidance llamará al método EnforceNonPenetrationConstraint antes de devolver el resultado calculado del steering. Esta función corregirá la posición de la entidad para asegurar que no se solapa sobre ningún obstáculo.

La verdad es que después de desarrollar este ejemplo me voy a pensar si saco o no una tercera parte... los steering behaviors dan mucho de sí... y existen otros comportamientos muy interesantes: evitar obstáculos que sean líneas, ocultarse, bloquear, asegurarse que los agentes no se solapan entre sí...

Os dejo el código en vuestras manos, tratádmelo bien! :-D

Posted: 9/1/2010 12:37 por Jesús Bosch | con 5 comment(s)
Archivado en: ,
[webcast] Iniciación a los Shaders personalizados en XNA

El XNA Game Studio Product Team empieza el año fuerte... ofreciéndo a la comunidad un webcast tecnológico en directo (en inglés). En concreto Shawn Hargreaves , uno de los desarrolladores del XNA Framework. ¿Quién mejor para hablar de XNA que sus propios creadores?  Aquellos que estamos en GMT+1 no nos va mal el horario... a pesar de ser en una zona horaria lejanísima, pero tendremos que madrugar. Si no me equivoco hay -9 horas de diferencia...

A hands-on demonstration of how to apply custom shaders to 2D sprites. Forget the complex 3D math, and no previous shader experience required – the goal is to achieve cool and interesting 2D effects in a simple and practical manner.

Para registrarse, hay que hacerlo en la siguiente URL: http://creators.xna.com/en-US/developerseries antes del 13/01/2010.

Posted: 7/1/2010 11:38 por Jesús Bosch | con 1 comment(s)
Archivado en: ,
[OT] Eureca!, portal de enlace al conocimiento

La Generalitat de Catalunya ha presentado el portal Eureca (Enlace Unificado a Recursos Electrónicos de Catalunya) , disponible en catalán, castellano e inglés. Contiene ingente información y documentación de universidades y otras instituciones culturales (Centro de Supercomputación, Instituto Cartográfico, etc). Para ser exactos contiene 170.000 documentos (y sigue creciendo).

www.eureca.cat

Posted: 5/1/2010 1:49 por Jesús Bosch | con 1 comment(s)
Archivado en:
[IA] Steering Behaviors en XNA (I de II)

Los Steering Behaviors son formas de comportamiento autónomas para agentes de un videojuego. El concepto y definición de los mismos proviene de Craig Reynolds. En esta serie de artículos propondré una implementación para algunos de estos steering behaviors, intentando hacerlo con un diseño lo más desacoplado, flexible y extensible posible. Todo ello intenentando superar mi primera aventura en el ámbito en este post anterior.

En este "episodio" os ofrezco la implementación de estos steering behaviors (uso denominaciones en inglés, ya que son las usadas en el mundillo y las que os facilitarán encontrar más información si lo necesitáis). No entro demasiado en la definición funcional de cada steering behavior, ya que puede encontrarse en el blog de Craig Reynolds. Ahí va un pequeño resumen:

  • Seek: Consiste en perseguir un objetivo o Target, intentando acercarse a él de forma directa.
  • Flee: Huye del Target, alejándose de él.
  • Arrive: El mismo behavior que el Seek, sólo que este reduce la velocidad suavemente antes de alcanzar el objetivo.
  • Pursuit: Persigue al Target con mayor "inteligencia", es decir, en vez de acercarse de forma directa al objetivo, realizaremos una estimación de su posición futura teniendo en cuenta el vector de velocidad en cada momento.
  • Evade: Al igual que el pursuit, intenta escapar del Target intentando estimar la posición futura del perseguidor, en lugar de alejarse de forma directa.
  • Wander: El agente se desplaza de forma errática, calculando un punto aleatório del área de un círculo situado enfrente del agente.

Mis favoritos son el Pursuit, que con un sencillo algoritmo genera una sensación de "inteligencia", y el Wander, que nos permite tener un agente que se desplaza de forma totalmente autónoma. Otro elemento a destacar es el diseño de esta implementación. Creo que es bastante flexible, aunque seguro es mejorable. Permite fácilmente integrar una máquina de estados finitos, para que el agente pueda cambiar de behavior en cualquier momento. Además podrían solaparse varios steering behaviors en un mismo agente a la vez... (aunque no tiene sentido solapar un seek y un flee, la utilidad de esto la veremos en la siguiente "entrega").

En el siguiente diagrama vemos que la clase SteeringBehaviors tiene instancias de otras clases, que representan cada uno de los comportamientos. Esto lo he hecho así para dotar de mayor flexibilidad a la implementación, y hacer el código menos complejo y por tanto más fácil de entender, mantener y extender. Cuando utilizemos esta clase desde cualquier juego para nuestros agentes, deberemos añadirles el Behavior con el método sobrecargado AddBehavior (con una sobrecarga para cada tipo de Behavior), y posteriormente llamando al método Update. El método update, el solito se encargará de ejecutar todos los steering behaviors que correspondan al agente. ¿Fácil, verdad?

Todos los steerings tienen una estructura común, aunque sus especializaciones pueden contener distintos atributos y métodos, como muestra este diagrama de ejemplo (no se incluyen todos los behaviors que contiene el código):

Como siempre os dejo el código adjunto para que lo provéis/uséis a vuestra conveniencia. Este vídeo refleja el resultado de la ejecución del programa:

 

Posted: 4/1/2010 13:42 por Jesús Bosch | con 11 comment(s)
Archivado en: ,
[XNA] DreamBuildPlay 2010: 100.000$ en premios por desarrollar un videojuego en XNA

Buenas noticias! Se ha abierto la convocatoria a uno de los concursos de desarrollo de videojuegos más jugosos: DreamBuildPlay 2010!  Y este año, además de poder ganar hasta 100.000$ (que no está nada mal), existe como premio adicional el hecho de que el juego será promocionado y vendido en XBOX Live! Eso significa... más dinerillo y bastante fama... recordemos que XBOX Live es un mercado mundial, con millones de usuarios y clientes potenciales.

Las bases son sencillas... tener al menos 16 años, vivir en uno de los países que pueden participar, y por supuesto... desarrollar un videojuego basado en la tecnología XNA Game Studio 3.1, todos los detalles e información puedes encontrarla en la web oficial del concurso:

http://www.dreambuildplay.com/main/default.aspx

[IA] Introducción a las máquinas de estado finito (Finite State Machines - FSM) - Parte II de II

En la primera parte vimos como una máquina de estados finitos permitía a una entidad de nuestro juego realizar una serie de acciones teniendo en cuenta algunos factores internos (hambre, cansancio, ganas de usar el WC...). Ahora veremos una versión mejorada de esta FSM, en la que entra en juego otra entidad, y la interacción entre ambas. Ahora pasaremos a tener la entidad Madre, además de la entidad Boy. Para que ambas FSM interactúen utilizaremos un sistema de mensajería entre objetos. Así pues la madre y el hijo se comunicarán entre sí (como tiene que ocurrir en toda buena familia).

En la primera versión, el niño, iba al WC cuando tenía ganas... ahora, además de eso, cuando haya terminado su estado de WCIng... volverá a la tarea a la que estaba anteriormente, fuera cual fuera (en la versión simplemente se ponía a jugar). Además, cuando tenga hambre, enviará un mensaje a su madre para que le haga la comida y seguirá con su tarea. Cuando la madre reciba el mensaje, dejará su tarea y se pondrá a hacer la comida, y cuando termine de hacerla, enviará un mensaje de notificación a su hijo, que ya podrá comer.

Esto podría implementarse sin sistema de mensajería... ignorando la estructura de la FSM y demás... pero es algo poco recomendable. Esta implementación (o cualquier mejora de ella), proporciona un código muy extensible, que encapsula muy bien la funcionalidad de la FSM, mejorando además su mantenibilidad. Observemos algunos cambios en el diseño de la entidad base:

Vemos que cada clase hija deberá implementar el método HandleMessage. Este lo que hará será llamar al método de manejo del mensaje en su instancia local de StateMachine. Esta, a su vez, enviará el mensaje al estado en el que se encuentre la clase. Hecho esto el mensaje será manejado... o no... esto dependerá de si el estado en el que se encuentra la entidad debe responder a ese mensaje.


Los mensajes son gestionados con la clase MessageDispatcher, que lo que permite es enviar estructuras del tipo Telegram entre entidades. Estos mensajes contienen el emisor/receptor, y el propio mensaje en sí mismo. Además contienen la propiedad "delay", por si queremos que la entidad receptora no reciba dicho mensaje hasta transcurrida X cantidad de milisegundos. Esto puede ser interesante por ejemplo en un juego en el que debemos esperar cierto tiempo (en un juego tipo command & conquer entrenaríamos un soldado y esperaríamos x tiempo a que finalizase el entrenamiento, transcurrido dicho tiempo, la unidad pasaría a estar disponible, notificándolo al sistema mediante uno de estos mensajes).

Otro cambio interesante es la clase StateMachine. Mediante la propiedad PreviousState puede volver a su estado anterior, si es necesario, tras finalizar la acción en su estado actual. Así, en el ejmplo que he implementado, el niño, tras usar el WC, volverá a la tarea en la que estaba anteriormente, fuera cual fuera. Esto dota de mayor dinamismo a la acción del juego.

Dejo el código disponible para quien quiera jugar con él o hacer propuestas de mejora!

Posted: 28/12/2009 13:46 por Jesús Bosch | con no comments |
Archivado en: ,,
[IA] Introducción a las máquinas de estado finito (Finite State Machines - FSM) - Parte I de II

Las Finite State Machines son uno de los medios mas utilizados desde tiempos inmemoriales en el desarrollo de videojuegos, con especial interés en la parte de Inteligencia Artificial. Si hablamos de IA en el más puro sentido académico... una FSM, por su propia definición, no sería inteligencia... pero sí permite simular inteligencia. En los videojuegos, al fin y al cabo, lo que queremos es que el jugador crea que está jugando contra una inteligencia, y que este, al vencer, sienta que es más inteligente que la máquina. Sí... siento decepcionarte pero así es, has vivido engañado, hasta hoy :-)

Las FSM permiten definir una serie de estados y que cada uno de ellos de un comportamiento distinto a las entidades que los contienen. Por ejemplo... un mísil tierra-aire podría tener los estados: Detenido (en el avión), Volando hacia vector fijo (una vez disparado), Persiguiendo objetivo (cuando está lo suficientemente cerca del avión enemigo).

El diseño de una FSM puede hacerse de muchas formas distintas... existen pseudo-patrones para ello (de hecho, no se les llaman patrones normalmente, lo hago yo porqué según he visto muchas personas y empresas los utilizan de forma común). Así pues, tendremos que intentar utilizar un diseño sólido (que puede basarse en uno de estos patrones) para no terminar teniendo un montón de código spagetti, y sobretodo, separar la lógica de cada entidad de la lógica de cada uno de los estados.


En el ejemplo de hoy utilizaré una idea muy básica y sencilla, que representa las acciones que hace un niño durante el día (y perdonad que sea tan simplista... es sólo un ejemplo!): Jugar, Comer, Dormir e ir al WC. Esto lo traduzco en los siguientes estados:

El diagrama es muuuuy sencillo, pero bueno, ya nos va bien para hacer unas pruebas, ¿no? Nuestra FSM se implementará del siguiente modo:

Por un lado tenemos la clase genérica State, de la cual heredan todos los estados. Esta clase asegura que todos los estados implementen el método Enter (cuando se entra en el estado), Execute (durante cada ciclo de ejecución), y Exit (cuando se sale del estado). Entonces cada clasae "hija" implementará esos métodos.

La clase Boy básicamente es una entidad, que es la que da sentido a la FSM, o cuyos estados son representados por la FSM. Los métodos interesantes son Update y ChangeState:

public override void Update(GameTime gameTime)
{
  
if(_currentState != null)
      _currentState.Execute(
this);
}

public void ChangeState(State<Boy> newState)

 
 // Salimos del estado actual
   if (_currentState != null)
      _currentState.Exit(
this); // El estado actual pasa a ser el nuevo estado
   _currentState = newState;

// Entramos en el estado
   _currentState.Enter(this);
}

Así de fácil! Ahora vamos a ver la implementación del estado Playing: 

public class Playing : State<Boy>
{
    

 

      if(entidad.IsWCNeed())
          entidad.ChangeState(
new WCing()); 

      if(entidad.IsFatigued())
         entidad.ChangeState(
new Sleeping()); 

      if (entidad.IsHungry())
         entidad.ChangeState(
new Eating());
   } 

entidad.Action = @"Playing>Execute> Jugando!";
   public
override void Execute(Boy entidad)
   {
      entidad.Fatigue += 1;
      entidad.Hungry += 1;
      entidad.WCNeed += 1;    public override void Exit(Boy entidad)
   {
      entidad.Action =
@"Playing>Exit> Apagando la consola...";
   }

   public override void Enter(Boy entidad)
   {
      entidad.Action =
@"Playing>Enter> Enciendo la consola...";
   }
}

Los string que se guardan en "Action" son los que utilizaremos para debugar. En realidad no serían necesarios en un juego real... pero dado que en este ejemplo no tenemos una interfaz gráfica nos irá perfecto para ver los estados por los que pasa la entidad Boy.

Este es el resultado de la ejecución:

La idea de cómo diseñar la FSM la he obtenido de este libro: Programming Game AI by Example, una verdadera joya que me recomendó un amigo y  su vez os recomiendo :-)

Posted: 16/12/2009 0:06 por Jesús Bosch | con no comments
Archivado en: ,,
[OT] MIT Open Courseware: Fuente de conocimiento infinita (o casi)

En esta web encontraréis cientos de cursos gratuitos de alto nivel sobre todos los temas... desde informática a física pasando por arquitectura, química o idiomas... El contenido de los cursos no tiene precio, y no lo digo sólo porque sean gratis... el nivel que tienen es universitario (y a veces incluso más). Encontraremos completísimos apuntes, vídeos, ejercicios resueltos e incluso exámenes. Algunos de los cursos incluso están traducidos a varios idiomas distintos al inglés, entre ellos el castellano.

La web acepta donativos... y sin duda esta es una buena causa.

El caso es que esta web hace años que existe... pero no la he descubierto hasta hoy... os la dejo para quienes, como yo, no la conocíais.

http://ocw.mit.edu/OcwWeb/web/courses/courses/index.htm o simplemente: http://ocw.mit.edu

Posted: 14/12/2009 12:47 por Jesús Bosch | con 2 comment(s) |
Archivado en:
Más artículos Página siguiente >