Jesús Bosch

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

August 2010 - Artículos

[GameDev] Recomendaciones de libros técnicos (xna y programación de videojuegos)

Los libros siempre han sido y serán grandes fuentes de aprendizaje. El caso es que la mayoría de libros de programación de videojuegos se escriben en inglés y no se llegan a traducir al castellano, así que si te quieres dedicar a esto mejor empieza por aprender inglés. Claro que una forma de hacerlo es precisamente leyendo libros en inglés! :-)

Primero comenzaré hablando de algunos libros que he leído entre 2009 y 2010 (glubs, haciendo recuento he visto que en ese tiempo me gasté más de 400$ en libros!). Los enlazo al Amazon de forma que si queréis podéis navegar por su índice de contenidos (yo siempre hago eso antes de comprar libros técnicos):

  • Learning XNA 3.0: Una introducción muy buena para principiantes. De hecho, fué el primer libro que me leí de XNA. Incluye una guía para desarrollar un pequeño juego 2D paso a paso, y otro tanto con un juego 3D.
  • XNA 3.0 Game Programming Recipies: Es una especie de recopilatorio de técnicas concretas. Muy interesante y de buen nivel, pero en mi opinión el libro no está muy bien organizado y eso lía un poco.
  • Microsoft XNA Game Studio Creator's Guide: Otra guía general de XNA, muy buena, explica todos los conceptos y da una visión general bastante buena del framework de XNA.
  • Mathematics and Physics for Programmers: Sí, no nos engañemos, la física y sobretodo las matemáticas son fundamentales en el desarrollo de videojuegos. Este libro me encanta, enseña un montón de conceptos de forma sencillísima. Hará que os encanten las matemáticas :-)
  • Artificial Intelligence for games: El libro está bien... incluye un montón de soluciones de IA, pero en mi opinión es muy genérico, hasta el punto de que los ejemplos se codifican con pseudocódigo (muy limitado para mi gusto). Incluso abandoné su lectura...
  • Pysics for Game Programmers: Un libro genial, se aprenden un montón de conceptos. Si no recuerdo mal los ejemplos vienen en C++, pero el código es fácilmente "traspasable" a C#.
  • Game Graphics Programming: Un libro que explica conceptos básicos de programación gráfica, desde qué es un triángulo a programación de shaders, texturas, sombras, iluminación... está muy bien para entender gran cantidad de conceptos, aunque el código es C++.
  • Programming Game AI by example: Un libro buenísimo, recomiendo enormemente su lectura. Explica conceptos de AI de forma entendible, y con un montón de ejemplos interesantes, en C++.
  • Game Development Essentials: An Introduction: No lo consideréis un libro de programación, ni siquiera un libro técnico. Habla de conceptos generales de videojuegos, muy útil para aprender conceptos de diseño, y conocer un poco como funciona la industria. El libro está muy bien organizado, con muchas fotografías, casi parece un libro de colegio :-)
  • Game Engine Architecture: Esta es mi última adquisición, de hecho lo estoy leyendo todavía actualmente. Parece ser un libro buenísimo que explica la distribución lógica que debe tener cualquier engine de videojuegos. Los juegos acostumbran a tener muchísimo código y las arquitecturas pueden llegar a ser un caos si no se trabaja de forma organizada, para mi una lectura imprescindible.

Otra fuente de recomendaciones de libros, del gran sitio gamedev.net, en inglés:
http://www.gamedev.net/columns/books/

Posted: 24/8/2010 7:30 por Jesús Bosch | con 7 comment(s)
Archivado en: ,,
[GameDev] Programación gráfica con OpenGL desde C#

Esto es simplemente una curiosidad. En Internet podéis encontarar distintos proyectos que permiten trabajar con Open GL desde código manejado (C#). Buscando un poco sobre el tema, el que me ha gustado más es Open TK. Esta es una librería que genera dll "multiplataforma", es decir, para .Net (Windows) y Mono (Linux, Mac OS X, y se está trabajando para que funcione también con Iphone) que nos permite trabajar con OpenGL 3.2. Es decir, que ya sea con MonoDevelop o Visual Studio podemos desarrollar juegos compatibles con la mayoría de PC's, todo ello con las ventajas de C#!

La librería es totalmente gratuita, y respecto a documentación, existe un manual de referencia de más de 1.700 páginas con información de todas las clases... A pesar de estas ventajas un servidor seguirá trabajando con XNA :-)

Para más información:
http://www.opentk.com

[GameDev] Descarga los engines de videojuegos desarrollados por Id Software

En el FTP de Id Software (ftp://ftp.idsoftware.com/idstuff/) podemos encontrar un montón de código fuente interesante de juegos completos, todos ellos escritos en la madre de todos los lenguajes: C o C++. Entre ellos se encuentran varias versiones de Doom, Quake, y recientemente ha sido liberado también el código de Return to Castle Wolfenstein.

¿Para qué nos sirve todo esto? Para aprender, aprender muchísimo! Claro, hay una enorme cantidad de código, y muchas cosas no las vamos a entender sin una documentación adecuada de la arquitectura, pero el código está ahí, se puede ver, tocar, e incluso compilar (si te atreves, y puedes).

Además de facilitar el aprendizaje, este código ha ayudado a la eclosión de una gran cantidad de MODS o versiones "modificadas" de estos juegos, versiones para otros dispositivos (como iPhone, Android o incluso Symbian!). Alguno de estos engines (a veces de pago, otras veces gratuitos) también ha facilitado la creación de nuevos juegos profesionales, como el motor de Unreal, que entre otros ha sido la base para Gears of War.

Algunos de estos mods, muchos de ellos Open Source, lo cual quiere decir que todavía tenemos más código para descargar y más engines a analizar. Algunos MODS de Quake:

 Prueba a buscar en Bing más mods, verás como hay decenas o incluso cientos de ello!

Compilar uno de estos juegos puede ser un reto, te atreves?

 

[C#] ¿Qué le pasa a todo el mundo? Las variables de tipo implícito no molaaan

Hoy hago un descanso de XNA para hablar de C# en general. Este lenguaje me gustaba sobre VB.NET por su "rudeza" en cuanto a la especificación de tipos y conversiones entre ellos se refiere, con un control de tipos fuerte y a prueba de "manazas", descartando muchos posibles errores humanos. El compilador actuaba como filtro de muchos errores que en otros lenguajes nos encontraríamos en tiempo de ejecución, y no en tiempo de compilación. Vamos, que si no codificabas bien no compilaba de ninguna de las maneras.

Pero en .Net 3.0 álguien decidió introducir "var" a C#, no se si para dar sentido a LINQ y los tipos anónimos, no se si para seguir tendencias, o no se si para hacerme la vida más difícil. Pues bien, gracias a esa decisión tenemos la suerte de podernos encontrar en C# con errores que bien podrían ser típicos de VB.NET, como por ejemplo esta conversión de tipos, que me ha petado en la cara al ejecutar un código hecho por un buen compañero (con su mejor intención por supuesto). Gracias Dios Microsoft por introducir el var en C#!

Si bueno, el var tiene sus ventajas, y supongo que será cuestión de gustos usarlo, pero yo os lo regalo para vosotros :-)

 

PD: Ojalá álguien me haga cambiar de opinión ofreciéndome una solución a este tipo de problemas de conversión de tipos en tiempo de ejecución!

[XNA] Austeridad geométrica en el render: Técnicas de culling

Un juego 3D incluye gran cantidad de modelos que sumados constituyen miles (o millones) de geometrías a renderizar. Dado que un juego tiene que ejecutarse en tiempo real, entre 30 y 60 fps, todo lo que hagamos debe ser óptimo, cualquier descuido o mala práctica puede convertir nuestro juego en una mala experiencia de usuario, y en definitiva en un fracaso técnico y comercial. Así pues, es clave optimizar el rendimiento.

Existen muchas técnicas para mejorar el rendimiento de un juego 3D. Quizá una de las más "directas" y fáciles de aplicar sea reducir el número de polígonos a procesar (que no siempre significa renderizar). Quiero decir que anque enviemos un montón de polígonos a la GPU, no necesariamente se van a renderizar todos, pero sí que esta perderá un montón de tiempo procesándolos (aplicando luz, aplicando Z buffers, etc). Así de sencillo. Lo bueno aquí es hacerlo sin que esto afecte a la calidad visual del juego en lo más mínimo. Sí, se puede hacer, con las distintas técnicas de culling de geometrías.

Existen múltiples técnicas de culling, vamos a conocer algunas de ellas.

 

Contribution culling

La técnica más fácil, implementada por defecto por la mayoría de engines 3D, y por supuesto también por XNA, consiste en no renderizar objetos que se encuentran tremendamente lejos, es decir, limitar el alcance de la cámara, o su "far clip". Lo hemos hecho todos cientos de veces al inicializar una cámara con el método Matrix.CreatePrespectiveFieldOfView (de este tema ya hablé en un artículo anterior). Lo mismo pasaría con el "near clip".

 

Backface culling

Consiste en NO renderizar los polígonos que no están orientados hacia la camara. Lo cierto es que la mayoría de engines 3D modernos como XNA, DirectX y OpenGL incorporan esta funcionalidad por defecto. Como comenta Jeff Weeks, la mitad de polígonos de un poliedro están de "espaldas" a la cámara, esto es, un 50% "directo" menos de polígonos a renderizar! En el artículo de Jeff podéis ver cómo funciona internamente esta técnica.

 

Frustum culling

En un post anterior escribí un ejemplo de funcionamiento de la optimización mediante Frustum Culling. Básicamente consiste en renderizar sólo los modelos que se encuentran dentro del frustum de la cámara. Con ello podemos tener un enorme mundo 3D en nuestro juego, pero sólo se renderizará aquella parte que sea visible por el jugador. Es una técnica muy fácil de utilizar, que creo que es imprescindible en cualquier juego 3D.

 

Occlusion culling

Consiste en no procesar los polígonos que se encuentran detrás de objetos opacos. Es decir, imaginemos que en nuestro juego el jugador está mirando a una pared, detrás de la cual (y dentro del frustum de la cámara), hay más objetos 3D. Si no hacemos nada, esos modelos 3D van a ser procesados igualmente por la GPU! Pues ahí es donde entran en escena los distintos algoritmos de Occlusion culling. Existen muchas formas de implementar esta idea, algunas de ellas con nombres verdaderamente fashion. De todos modos os recomiendo que antes que nada echéis un vistazo a este código, a veces unas líneas de código valen más que mil palabras, este se basa en la clase OcclusionQuery del XNA Framework. También es interesante la aplicación que el ejemplo hace del occlusion culling, que en este caso no la usa para optimizar el rendimiento. Ahí va el resumen de algunas técnicas de occlusion culling:

  • Portal rendering: Consiste en un sistema de occlusion culling basado en celdas conectadas por "portales". Esto es, dividimos nuestro mundo 3D en celdas imaginarias o lógicas. Algunas de ellas se encuentran conectadas. Dicho esto, si tenemos las celdas 1, 2 y 3, sabemos que desde la 1 se ve la 2, y que desde la 2 se ve la 3, podemos saber que si el jugador se encuentra en la celda 1 no necesitamos renderizar la celda 3!
  • Potentially visible set (PVS): Podría decirse que es algo parecido al mecanismo anterior (al final que el objetivo es el mismo), sólo que los objetos potencialmente visibles / renderizables son calculados en tiempo de ejecución, lo cual puede suponer algo de tiempo de procesamiento. Un ejemplo de esto serían las rejillas de vóxels, de las que tengo un ejemplo en un artículo previo o los octrees.

 

En resumen, es interesante aplicar estas técnicas en nuestros juegos, y a ser posible hacerlo en una capa lógica distinta a la que pueda contener el gameplay, de forma que sea independiente de nuestro juego, facilitando la reutilización de este componente gráfico. Aplicando las técnicas de oclusión los juegos 3D deberían experimentar una notable mejora de rendimiento.

 

Para saber más:

Los libros que os recomiendo los he leído todos, y hablan del tema en mayor o en menor medida. Los enlaces han sido fuentes bibliográficas para este artículo.

[OT] ¿Ya conoces XNA Community?

XNA Community es una comunidad de desarrolladores de XNA de habla hispana, es decir, que engloba personas de España y Latinoamérica principalmente. Muchos somos los que colaboramos aportando artículos, tutoriales, ejemplos a la comunidad.

En la wiki que tenemos en codeplex tenemos cientos de ejemplos, desde shaders hasta algoritmos de inteligencia artificial, pasando por implementaciones de simulaciones física, juegos completos 2D y 3D, todo ello con código incluido. Cualquier programador, por novato que sea, puede solicitar el acceso a la wiki y colaborar con artículos, ya que se hablan de multitud de temas y de todos los niveles de dificultad.

Por otro lado la comunidad dispone de un foro en el que las preguntas son respondidas rápidamente por algunos de los mejores XNAeros hispanohablantes.

Además, en el sitio de MSDN España, en la sección de XNA, nuestra comunidad ha aportado y aporta gran parte de su contenido.

Finalmente, tenemos un grupo en Facebook en el que vamos colgando artículos, noticias, etc, donde ya somos más de 300 miembros!

Os dejo con los enlaces!

Visita nuestra wiki:
http://xnacommunity.codeplex.com/

Visita nuestro foro:
http://www.dotnetclubs.com/forums/44.aspx

MSDN España - Centro de desarrollo XNA:
http://msdn.microsoft.com/es-es/xna/default.aspx

Grupo de facebook:
http://www.facebook.com/#!/pages/XNA-Community/162473609100

[XNA] Más cambios en la API de XNA 4.0, wireframes

Shawn Hargreaves, del XNA Team explica de forma extensa los cambios en los objetos de estado en XNA 4.0 -o sea que no voy a repetir o traducir su artículo-. Lo que sí que voy a hacer es poner un pequeño ejemplo de como usar estos nuevos objeots para renderizar un modelo 3D sin su textura, y sin rellenar los triángulos, "pintando" sólo las aristas, es decir, renderizar su wireframe. Lo que vendría a ser algo así:

¿Para qué sirve renderizar un modelo en forma de wireframes? En mi opinión puede ser muy útil para debugar, para analizar el comportamiento de nuestros modelos ante nuestras rutinas de detección de colisiones por ejemplo, o contra un posible engine de físicas.

En XNA es muy fácil decirle a la tarjeta gráfica si debe renderizar el wireframe o bien todo el modelo con sus texturas y demás. En XNA 3.1 esto lo hacíamos así:

GraphicsDevice.RenderState.FillMode = FillMode.WireFrame;

Así de simple! Ahí va un ejemplo de como quedaría la cosa:

Lo cierto es que en XNA 4.0 no es más difícil, pero sí que ha cambiado. Es uno de los cambios "molestos" con los que me he encontrado en un proyecto personal -y de aquí a que lo comparta con vosotros, además que la documentación de estas clases en el MSDN digamos que es quizá un poco "breve"-. Se haría de la forma siguiente:

RasterizerState raster = new RasterizerState();

raster.FillMode =
FillMode.WireFrame;
GraphicsDevice.RasterizerState = raster;

Este sería un ejemplo en XNA 4.0, y además sobre el emulador de Windows Phone 7:

Lo "molesto" es que hay que instanciar un objeto "RasterizerState", pero tampoco es el fin del mundo verdad?

Posted: 12/8/2010 8:55 por Jesús Bosch | con 5 comment(s)
Archivado en: ,,,
[XNA] Recopilación de posts de mi antiguo blog

Antes de formar parte de la comunidad Geeks tenía un blog en wordpress, escrito mayormente en catalán. En esos tiempos estaba comenzando con esto del XNA, pero la verdad es que algunos artículos son bastante interesantes. "Moverlos" supone invertir un tiempo del que no dispongo de momento (espero hacerlo antes de morir de viejo), pero sí que voy a enlazar los que más me gustan. Personlamente me traen muy buenos recuerdos. Son estos:

En la mayoría de enlaces está el código de ejemplo, si falla algún enlace de un ejemplo que queráis me enviáis un comment o mensaje y miramos a ver si lo tengo por algún lado.

Posted: 12/8/2010 8:45 por Jesús Bosch | con 1 comment(s)
Archivado en:
[XNA] El arte de saber tocar: arrastrar y soltar modelos 3D

Waw! Una de las cosas a la que tenía ganas de echarle mano (literalmente) es a la codificación del touch en el nuevo Windows Phone 7. Encima he tenido tiempo de leer el artículo al respecto de Nick Gravelyn (del XNA Team). Digamos que en XNA 4.0 para Windows Phone 7 tenemos acceso al touch programáticamente de dos formas posibles:

  • Lectura directa del touch
  • Lectura "interpretada" de gestos (interpretada por el propio framework)

Toda esta maravilla se encuentra en: Microsoft.Xna.Framework.Input.Touch.

En ocasiones nos puede interesar interpretar directamente el touch, por ejemplo, sólo queremos saber si el jugador está tocando la pantalla, nos da igual el gesto que haga. Como en este jueguecillo en el que estoy trabajando:

Aquí lo que estoy haciendo es leer del TouchCollection el primer "toque" que el usuario hace sobre la pantalla (touches[0], recordemos que WP7 puede leer hasta 5 touches a la vez). Después trazo un rayo para ver si la posición del dedo, y teniendo en cuenta la dirección del frustum de la cámara, intersecciona con la bola. Si esto sucede muevo la bola en el eje de las X. Cuando el estado del touch pasa a Release (el usuario deja de tocar el teléfono), lanzo la bola hacia el eje de las Z.

Esto se hace fácilmente de la siguiente forma en el método Update del juego:

   1:              TouchCollection touches = TouchPanel.GetState();
   2:              Vector3 posicionReal = Vector3.Zero;
   3:   
   4:              // Manejamos el "coger" la bola
   5:              if (touches.Count > 0)
   6:              {
   7:                  // Si estamos moviendo el dedo...
   8:                  if (touches[0].State == TouchLocationState.Pressed 
   9:                   || touches[0].State == TouchLocationState.Moved)
  10:                  { 
  11:                      posicionReal = ColisionDedoBola(touches[0].Position);
  12:   
  13:                      posicionTouch = touches[0].Position;
  14:                      posicionTouch3D = posicionReal;
  15:   
  16:                      if (posicionReal != Vector3.Zero)
  17:                      {
  18:                          // Bloqueo la Y
  19:                          posicionReal.Y = entidadFisicaBola.worldTransform.Translation.Y;
  20:                          // Bloqueo la Z
  21:                          posicionReal.Z = entidadFisicaBola.worldTransform.Translation.Z;
  22:   
  23:                          // Muevo la bola
  24:                          entidadFisicaBola.worldTransform = Matrix.CreateTranslation(posicionReal);
  25:                      }
  26:                  }
  27:                  // Si soltamos la bola...
  28:                  else if (touches[0].State == TouchLocationState.Released 
                           && estadoPrevioTouch != TouchLocationState.Invalid
  29:                      && ColisionDedoBola(touches[0].Position)!= Vector3.Zero)
  30:                  {
  31:                      Vector3 velocidadLienal = -Vector3.UnitZ * 50.0f;
  32:   
  33:                      Random rand = new Random(gameTime.TotalGameTime.Milliseconds);
  34:   
  35:                      double aleatoriedad = rand.NextDouble();
  36:                      int signo = rand.Next(0, 1);
  37:                      
  38:                      if(signo==0)
  39:                          velocidadLienal += new Vector3((float)aleatoriedad, 0, 0);
  40:                      else
  41:                          velocidadLienal += new Vector3(-(float)aleatoriedad, 0, 0);
  42:   
  43:                      entidadFisicaBola.linearVelocity = velocidadLienal;
  44:                      entidadFisicaBola.becomeDynamic(20.0f);
  45:                  }
  46:                  
  47:                  estadoPrevioTouch = touches[0].State;
  48:              }

Si quisieramos hacer una interpretación más avanzada de los movimientos del usuario, habría podido utilizar la API de los gestos. Lo primero sería inicializar los gestos:

TouchPanel.EnabledGestures =
    GestureType.Tap |
    GestureType.DoubleTap |
    GestureType.FreeDrag;

Aquí estamos diciendo qué gestos queremos tener habilitados (la lista completa podéis consultarla en el blog de Nick). Una vez habilitados los gestos, en el método Update del juego nos limitaremos a actuar cuando se produzca cualquiera de estos:

while (TouchPanel.IsGestureAvailable)
{
    GestureSample gesture = TouchPanel.ReadGesture();

    switch (gesture.GestureType)
    {
        // TODO: handle the gestures
    }
}

Vale, el touch no tiene secretos, ¿verdad? A mi lo que me gusta más de este código es el método ColisionDedoBola. Este lo que hace es devolver un vector 3D en el “mundo” del juego, que sería el punto en el que el rayo trazado a partir de la posición del dedo colisiona con la bola. Este es el código para dicho método:

   1:          private Vector3 ColisionDedoBola(Vector2 touch)
   2:          {
   3:              Vector3 origenRayo;
   4:              Vector3 destinoRayo, direccionRayo;
   5:   
   6:              origenRayo = GraphicsDevice.Viewport.Unproject(
                        new Vector3(touch.X, touch.Y, 0), camara.projection, camara.view, Matrix.Identity);
   7:              destinoRayo = GraphicsDevice.Viewport.Unproject(new Vector3(touch.X, touch.Y, 1), camara.projection, camara.view, Matrix.Identity);
   8:              direccionRayo = Vector3.Normalize(destinoRayo - origenRayo);
   9:   
  10:              float toi;
  11:              Entity entidadHit;
  12:              Vector3 puntoHit, normalHit;
  13:   
  14:              if (this.space.rayCast(origenRayo, direccionRayo, 1000, 
                       false, out entidadHit, out puntoHit, out normalHit, out toi))
  15:              {
  16:                  if (entidadHit!=null && entidadHit.GetType() == typeof(Sphere))
  17:                  {
  18:                      Vector3 posicionFinal = origenRayo + direccionRayo * toi;
  19:   
  20:                      return posicionFinal;
  21:                  }
  22:              }
  23:   
  24:              return Vector3.Zero;
  25:          }

La gracia del asunto está en el método Unproject del Viewport del objeto GraphicsDevice. Por otro lado el ray cast lo hago usando un método del engine de físicas que estoy utilizando, pero sería igualmente sencillo con la clase Ray propia del Framework de XNA. Dado que en un artículo anterior escribí sobre el trazado de rayos, no voy a repetirme.

Para quien quiera trastear más con el touch: ya que sólo unos pocos afortunados disponen del dispositivo físico, y la mayoría de mortales nos tenemos que conformar con el emulador, el touch en este software lo que hace es emular el toque a través de las pulsaciones con el mouse. Lo primero que pensarán muchos es: ¿cómo emulo entonces el multitouch? Pues con dos ratones :-P Existe un proyecto en codeplex de una herramienta –Multi Touch Vista- que precisamente nos permite trabajar con dos ratones al mismo tiempo (puede parecer raro pero es un experimento interesante).

Posted: 8/8/2010 9:48 por Jesús Bosch | con 6 comment(s)
Archivado en: ,,,