[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…).

[View:http://www.youtube.com/watch?v=7IOTrqlz4jo:550:0]

[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.

[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í! 😀

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:

[View:http://www.youtube.com/watch?v=8acCnWESKf8:550:0]

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…

[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…

[View:http://www.youtube.com/watch?v=VaXtnqjk4Bc:550:0]

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.

[View:http://www.youtube.com/watch?v=tAWNp1gRxQE:550:0]

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

[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:

[View:http://www.youtube.com/watch?v=Xw0T9m1hcwA:550:0]

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 😛

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! 😀

[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.

[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

[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:

 [View:http://www.youtube.com/watch?v=JLoU7SQZCmM:550:0]

[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 🙂