Jesús Bosch

XNA y desarrollo de videojuegos por un Microsoft Student Partner
[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 4 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 10 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:
[XNA] Conéctate a XNA Creators Club y vende tus juegos en XBOX 360 Indie Games

Hoy os explico qué necesitamos para desplegar nuestros juegos hechos con XNA sobre XBOX 360, e incluso ponerlos a la venta en XBOX Live Indie Games y sacarnos algún dinerillo con ello. Todo ello sin sacar un euro de nuestros bolsillos. Antes que nada, advertir que no puede subir juegos a XBOX Live Indie Games máquinas desde cualquier país. Por algún motivo que desconozco (pero que seguro que tiene algún sentido), sólo pueden subirse juegos desde alguno de los países siguientes:

  •  Australia, Canada, Denmark, France, Ireland, Italy, Netherlands, New Zealand, Norway, Singapore, Spain, Sweden, Germany, Japan, United Kingdom, y United States


- Conexión a Internet -aunque si lees esto será que ya tienes :-P
- XBOX 360
- Ordenador conectado a la misma red que la XBOX, con Visual Studio (en cualquiera de sus ediciones), XNA Game Studio, y por supuesto una aplicación hecha en XNA
- Cuenta de Creators Club (es de pago, pero veremos como obtener una cuenta gratuita)


Lo primero será iniciar la XBOX y conectarnos a XBOX Live, es un proceso totalmente gratuito y bastante trivial, así que no entraré en detalle en este asunto. Sólo recuerda que cuando te registres el sistema te ofrece la opción de conectarte pagando (suscripción GOLD) o sin pagar (suscripción SILVER). La diferencia entre ambas cuentas es que con la suscripción GOLD puedes jugar online, conectarte a Facebook o twitter desde la XBOX... pero a nosotros, para publicar juegos de XNA a XBOX, nos vale con una cuenta SILVER. Tras el registro tendremos nuestro nuevo GAMERTAG.

Una vez hecho esto... necesitamos registrarnos a la web de XNA Creators, para ello accede y regístrate a la siguiente web: http://creators.xna.com, este registro es gratuito. Una vez registrados veremos que tenemos la opción de tener una suscripción GOLD del creators club (que no es lo mismo que la suscripción GOLD de XBOX Live). El caso es que no necesitamos una suscripción gold para que funcione... con una Trial nos vale (tiene menos funcionalidades, pero nos vale para lo que queremos hacer). ¿Cómo hacemos para obtener una cuenta Trial? Si eres estudiante de FP o Universidad estás de suerte, porqué de forma fácil puedes obtener una, en www.dreamspark.com, o mediante el DotNetClub de tu centro de estudios (www.dotnetclubs.com), en mi caso, el de la UOC, del que soy coordinador: http://uoc.dotnetclubs.com. Si en tu centro de estudios no existe ningún dotnetclub... crea tu uno!

Vale, tenemos la suscripción a XBOX Live Silver, la cuenta de Creators y la suscripción XNA Creators Club (Trial). Ahora necesitamos asociar la suscripción Trial con nuestro gamertag. Para ello accede de nuevo a http://creators.xna.com, haz login y ve a "editar perfil", allí, en la parte inferior de la pantalla, tienes una opción que pone "Asociar con mi gamertag". Y con esto hemos acabado por lo que a registros se refiere...

Ahora ve a XBOX Live, y conéctate al Bazer de Juegos, ve a la pantalla que los muestra todos por orden alfabético, y ve a la X (de XNA claro), y allí podrás descargar e instalar en tu XBOX el XNA Game Studio Device Center. Una vez descargado... ejecútalo. Te dará una especie de número de serie.

Ahora ve a tu PC y abre cualquier proyecto que tengas en XNA (que no utilice librerías COM ni cosas raras, porqué en cuyo caso en XBOX no va a funcionar), pulsa con el botón derecho sobre el nombre del proyecto y marca la opción: "Create a Copy of project for XBOX 360". Esto lo que hará es crear una copia idéntica del proyecto en la solución, pero que será ejecutable en XBOX 360. Establece el proyecto como proyecto de inicio, pulsando con el botón derecho sobre el, como antes, y marcando la opción "Set as startup project" (o "Establecer como proyecto de inicio", yo lo tengo en inglés...). Ahora, en el menú de Visual studio, ve a VIEW->TOOLBARS, y asegúrate que está activada la toolbar: "XNA Game Studio Device Management".

Para conectar a la XBOX, pulsa el botón cuyo icono es una cruz verde (Add a new device), y selecciona la XBOX 360. Entonces se te pedirá una descripción para el dispositivo y un "número de serie", es el número que aparece en la XBOX, introdúcelo y acepta. Con esto ya habrás habilitado la ejecución de aplicaciones XNA sobre XBOX 360. Selecciona en el desplegable de la misma toolbar el dispositivo que acabas de crear y compila.

Tu juego debería estar ejecutándose en XBOX 360 :-)  Recuerda que si tu juego es lo suficientemente bueno... podrías llegar a colgarlo en XBOX Live Indie Games. Puedes echar un vistazo a los Indie Games existentes en el Bazar de Juegos de XBOX Live, e incluso bajarte demos gratis para probarlos.

Cuidado porque si XNA y XBOX ya son adictivos por separado... imagíante juntos! :-)

 

Posted: 14/12/2009 9:00 por Jesús Bosch | con 5 comment(s) |
Archivado en: ,
[XNA] Realizar capturas de pantalla de nuestros juegos hechos en XNA

¿Cómo ofrecer la funcionalidad al usuario de realizar capturas de pantalla de nuestros juegos en XNA? Como siempre XNA nos facilita este tipo de cosas tan elementales, de forma que podamos reservar nuestra cabeza para dedicarla a cosas más complejas... En esta ocasión las clases ResolveTexture2D y PresentationParameters hará todo el trabajo por nosotros.

El código es muy sencillo... y es el que os presento a continuación

PresentationParameters parametros = GraphicsDevice.PresentationParameters;

ResolveTexture2D datosTextura = new ResolveTexture2D(GraphicsDevice, parametros.BackBufferWidth, parametros.BackBufferHeight, 1, GraphicsDevice.DisplayMode.Format);

GraphicsDevice.ResolveBackBuffer(datosTextura);

datosTextura.Save(@"c:\captura.png", ImageFileFormat.Png);

Tenemos una instancia de PresentationParameters, que a su vez utilizamos para inicializar una instancia del objeto ResolveTexture2D. A continuación llamamos al método ResolveBackBuffer del GraphicsDevice, que lo que hace es precisamente pasar los datos del backbuffer a nuestra instancia de ResolveTexture2D. Finalmente esta misma instancia tiene el método Save, que nos permitirá guardar nuestra captura como archivo en multitud de formatos gráficos: Bmp, Dds, Dib, Hdr, Jpg, Pfm, Png, Ppm, Tga (incluso diría que demasiados formatos, la mitad ni siquiera los conozco...).

La clase PresentationParameters es muy interesante -podríamos haber utilizado dicha propiedad directamente en el GraphicsDevice con los mismos resultados-, tiene información del BackBuffer, podemos saber si estamos utilizando antialias (multisampling) así como establecer su calidad, si estamos en pantalla completa, etc.

Os dejo con mi captura de pantalla y el proyecto de Visual Studio completo para el que quiera probarlo.

Posted: 3/12/2009 20:34 por Jesús Bosch | con no comments
Archivado en:
[evento] Termens Lan Party, con charla de XNA incluida

No sólo de jugar vive el hombre...(pero casi) Para quienes estéis por la zona de Catalunya -los de Lleida no tenéis excusa-, os recomiendo que os paséis por la Termens Lan Party, la última Lan Party importante del año, donde además de los juegos y las descargas de toda Lan Party que se precie encontraremos buenas charlas y varios talleres interesantes. Entre los cientos de frikis reunidos, uno de ellos será un servidor, donde daré una charla de XNA. Imagino que en este tipo de sitios hay mucha gente joven, la mayoría seguramente no es profesional de la informática, así que mi reto será conseguir que los asistentes compilen sus primeras líneas de código en XNA y consigan mover algo por la pantalla... y no asustar a nadie con las matrices xD

Será una buena oportunidad para encontrarnos y amortizar las targetas gráficas de nuestros PC's... A los que os paséis por allí no dudéis en pasaros a saludar y comentamos la jugada (y echamos unas partidas) :-)

[XNA] Detección de movimientos con una webcam (II de II)

En el artículo anterior describí unos sensores en determinadas zonas de la textura captada por nuestra webcam. Mediante estos sensores se pueden hacer distintas cosas, así a voz de pronto se me ocurre: pintar en pantalla con los dedos (sin tocarla obviamente xD), tocar un piano..., y otra que puede tener una utilidad más inmediata en videojuegos... mover o esquivar objetos. Lo que vamos a hacer pues será eso. Dado un modelo 3D como el de la fotografía, trataremos de moverlo por la pantalla.

Para ver como funcionan los sensores, habilitaremos dos viewports que dividirán la pantalla en dos zonas. La superior mostrará la textura tomada por la cámara y los sensores (estado y posición), y la parte inferior mostrará el modelo renderizado. La gracia del asunto está en que usaremos dos sensores, y la nave rotará hacia a la izquierda o derecha dependiendo de qué sensor activemos.

La posible complegidad algorítmica está resuelta en el artículo anterior... mover la nave resultará ahora trivial:

protected override void Update(GameTime gameTime)
{
   
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
      
this.Exit();

    sensorDerecha.Update(gameTime,
this.capture.colorData, this.capture.CurrentFrame);
    sensorIzquierda.Update(gameTime,
this.capture.colorData, this.capture.CurrentFrame);

   
float direccion = 0;

   
if(sensorIzquierda.hayCambio)
         direccion -= 0.01f;
   
if(sensorDerecha.hayCambio)
         direccion += 0.01f;

    mundo *=
Matrix.CreateRotationZ(direccion);

    base.Update(gameTime);
}

Se ve rápidamente que llamamos a la lógica de cada sensor, y a continuación utilizamos la información de estos sensores para rotar la nave hacia una dirección u otra, respecto el eje Z.

Otra pequeña particularidad que puede tener este código es que utiliza dos viewports en lugar de uno. Esto permite dividir la pantalla en N zonas de renderizado (en este caso dos). Esto se acostumbra a utilizar para los videojuegos multijugador, en que cada player tiene su trozo de pantalla.

Este es el resultado del experimento (el código se encuentra adjunto a este artículo):

 

Editado: He subido una versión actualizada del código, la nave giraba al revés!! (izquierda al levantar la mano derecha y derecha al levantar la mano izquierda), si es que no se puede trabajar a esas horas de la noche... :-)

[XNA] Detección de movimientos con una webcam (I de II)

Este artículo comienza como una serie de experimentos con la interacción jugador-XNA mediante webcam. En esta primera parte simplemente procederé a detectar movimientos en ciertas zonas de la pantalla con lo que denominaremos "sensores". Una vez calibrados y controlados estos sensores, podremos experimentar con formas de interacción poco habituales. Por ejemplo, podremos hacer que una nave en 3D gire hacia la derecha o hacia la izquierda, dependiendo de los sensores que "activemos". Estos sensores podrían ser dos, uno a cada lado de la pantalla, de forma que sean sensibles a los movimientos de la mano del usuario. Así levantando la mano hacia la derecha, nuestra nave rotará en esa dirección, y viceversa si levantamos la mano izquierda. En definitiva, tendremos una respuesta virtual a tiempo real a nuestra interacción. Todo esto supondría trabajar algunos aspectos básicos de la realidad virtual.

Dicho así todo esto puede sonar un poco complicado... pero como siempre, una imagen puede aclararnos más que mil palabras -nótese que la captura está tomada cerca de las 3 de la madrugada, y uno comienza a estar roto a esas horas...-. En la captura se ve rápidamente que hay dos cuadros en la pantalla, el de la izquierda está en color blanco, y el de la derecha está en rojo. Esto es así porque hay un cambio en el color en esa zona dentro del recuadro (a continuación veremos el algoritmo utilizado en detalle).

Antes de entrar en mayores detalles, indicaré que no explicaré la entrada de vídeo desde la Webcam a XNA, básicamente porque estoy reutilizando una clase implementada por Javi Cantón para ello. Para mi este componente es una "caja negra", en mi aplicación tengo una entrada de vídeo y listos, esta, va actualizando una textura y sus datos relacionados. Si queréis utilizar ese componente está dentro de mi código (tenéis un link al final del artículo), o de forma alternativa podéis bajarlo en XNA Community. Otra clase de terceros que utilizo en el proyecto es Primitive2D, que básicamente permite dibujar gráficos simples 2D basados en primitivas (como su descriptivo nombre indica), no pongo el enlace al autor porque desconozco quién es :-). Y dicho esto... podemos comenzar.

La clase principal de esta aplicación sin duda es "SensorColores". Esta clase, será responsable de controlar los cambios de la primera captura de pantalla tomada mediante webcam con la actual en cada llamada al método Update().

 

Para entender su funcionamiento será interesante explicar los campos de la clase:

  • colors2DPrevio: Guarda los datos de la textura anterior a la actual, es decir, contra la que queremos comprobar si han habido cambios. En mi implementación, sólo tomaremos una captura de pantalla al inicio de la ejecución, y contra esa haremos el resto de comprobaciones de si hay movimiento o no. Este campo es un array de dos dimensiones, que contiene la información de todos los píxels de la textura.
  • densidadZona: Hemos dicho que definiríamos unas zonas "sensibles", o sensores, y en ellas se comprobaría si el color de los píxels son distintos respecto el frame anterior. Lo que ocurre es que si tenemos una zona o sensor muy grande, recorrer todos los píxels de la misma sería un proceso demasiado lento, y podría afectar al rendimiento. La densidad indica el número de píxels que nos "saltaremos" en el momento de recorrerlos en busca de cambios. Es decir, si el valor es 5, iremos de 5 en 5 píxels, en lugar de ir de 1 en 1. Esto hace que recorrer todo el array sea mucho más rápido. En realidad nos limitamos a hacer un muestreo de la zona, en lugar de un análisis completo, que entendemos que nos daría unos resultados similares.
  • primitiva: Sólo se utiliza para pintar los cuadros en pantalla, así que aquí no tiene mucha importancia, solo diremos que el color de la misma variará en función de si se han detectado cambios o no en el frame actual respecto el frame anterior.
  • tiempo: Indica el tiempo transcurrido, en milisegundos, desde la primera llamada al método Update de esta clase. Esta variable podría ser útil para variaciones en la implementación del algoritmo, que veremos luego.
  • toleranciaCambio: Este sí que es un atributo interesante. La diferencia de los colores entre dos fotogramas a color, que enfoquen a una persona inmóvil pueden parecer prácticamente iguales a la vista humana, pero la realidad es que las imágenes están absolutamente llenas de "ruido" -exceptuando que tengamos una super cámara de vídeo de muy alta resolución-. Para decidir si dos píxeles son distintos, seremos algo "tolerantes", y no miraremos que sus códigos de color sean exactamente iguales, sinó que tengan un cierto parecido. La permisividad en este parecido será el valor de esta variable. Si descargas el código y lo pruebas en tu máquina, deberás jugar con el valor de esta propiedad, incrementándolo y decrementándolo hasta alcanzar un nivel adecuado para la iluminación del espacio en el que te encuentres (en la próxima versión puede que incluya un calibrador automático).
  • zonaSensor: Define el área de pantalla que se analizará para combprobar las diferencias en los colores.

Explicado todo esto... ya podemos ver el código del método Update de la clase SensorColores, que donde está lo realmente interesante. Este método será llamado a su vez por el método Update de la clase Game.

El primer punto destacado es este método:

Color[,] colors2D = TextureTo2DArray(color, textura);

Lo que hacemos es pasar la información de la textura, que es un array unidimensional (color) a un array de dos dimensiones. Vosotros diréis lo que os parezca, pero a mi me es más fácil tratar un array en dos dimensiones cuando tengo que referirme a posiciones X e Y de una textura. Lo realmente importante del algoritmo es que estamos transformando sólo los píxels de interés para el análisis, es decir, aquellos que se encuentran en la zona del "sensor", y además aquellos que se encuentran afectados por el factor de "densidad" (esto se puede observar en el incremento de las variables al final de cada bucle while).

private Color[,] TextureTo2DArray(Color[] color, Texture2D textura)
{
    
Color[,] colors2D = new Color[textura.Width, textura.Height];
    
int p = zonaSensor.X;
    
int q = zonaSensor.Y; 

    // Incrementamos segn la densidad de la zona, para no perder rendimiento
   
while
  
 (p < (textura.Width - 1) - densidadZona)
    {
       
while
        (
q < (textura.Height - 1) - densidadZona)
        {
            colors2D[p, q] = color[p + q * textura.Width];
            q += densidadZona;
        }
        p += densidadZona;
    }
   
return colors2D;

Finalmente entramos en el "core" del algoritmo. Un aviso: este algoritmo me lo he inventado yo, no puedo garantizar ni que sea "el método" de hacer esto (puede que existan otras formas de hacerlo) ni tampoco el mejor  -si existen otras formas, es posible que alguna de ellas sea mejor :-)

 // Solo entramos en el bucle si hemos pasado por un frame previamente,
 
// sin no tiene sentido hacer los clculos
if (colors2DPrevio != null)
{
   
int pixelsCambio = 0;
   
int pixelsIguales = 0;
   
int xMin = zonaSensor.X;
   
int xMax = zonaSensor.X + zonaSensor.Width;
    int yMin = zonaSensor.Y;
   
int yMax = zonaSensor.Y + zonaSensor.Height;

    // Recorremos los pxels del sensor en busca de cambios
   
int x = zonaSensor.X;
   
int y = zonaSensor.Y;

    while
   (x < (xMax - 1) - densidadZona)
   {
        
while
       
(y < (yMax - 1) - densidadZona)
        {
           
int color1 = Math.Abs((int)colors2D[x, y].PackedValue);
           
int color2 = Math.Abs((int)colors2DPrevio[x, y].PackedValue);
           
           
// Si superamos la tolerancia al cambio... incrementamos el nmero de pxels con cambio
          
if (Math.Abs(color1 - color2) > toleranciaCambio)
           {
                pixelsCambio++;
           }
          
else
          
{
               pixelsIguales++;
           }

          
// Incrementamos Y segn la densidad definida
         
y += densidadZona;
       }

   // Incrementamos X segn la densidad definida
   x += densidadZona;
   }

    // Si hay ms pxeles distintos que iguales, entonces dedidimos que hay un cambio
    if(pixelsCambio > pixelsIguales)
    {
        hayCambio =
true;
        primitiva.Colour = 
Color.Red;
    }
    else
    {
        hayCambio =
false;
        primitiva.Colour =
Color.White;
    }
}

// Finalizado el proceso... guardamos los datos en coloresPrevios
if (colors2DPrevio == null && tiempo >= 1000)  
{
    colors2DPrevio =
new Color[colors2D.GetLength(0), colors2D.GetLength(1)];
}


Aquí os dejo un vídeo de como quedaría todo:

 Nota del vídeo: El vídeo aparece en blanco y negro, eso es porqué en el momento de grabar el vídeo hice unas pruebas con un shader de escala de grises. En la versión de código que os podéis descargar la imagen de la webcam aparece en color.

Como habréis observado, más que detección de movimiento, lo que hago en este experimento sería detectar los cambios de color o los cambios en la imagen desde "fotograma actual" - N al "fotograma actual". Y nada... en el próximo "episodio" haremos lo más fácil, pero bonito a la vez, mover o rotar un objeto en la pantalla en función de los movimientos que haga el jugador delante de la cámara. Además prometo no salir en el vídeo :-P

Posted: 24/11/2009 2:30 por Jesús Bosch | con 6 comment(s) |
Archivado en: ,
[webcast] Gestión de proyectos para Xbox Live Indie Games

En este evento organizado por el UOC DotNetClub y XNA Community tendremos con nosotros a Mauricio García, Jefe de Proyectos en Nivel 21. En el historial de su equipo destaca el reciente juego Rotor's Scope, ganador del segundo premio en el prestigioso concurso internacional: Dream Build Play, en la edición de 2009. Este desarrollo podría describirse como genial, contiene innovaciones como el hecho de estar inmerso en un juego de tipo puzzle ya de por sí con una jugabilidad nunca vista en este tipo de plataforma, que se apoya en un desarrollado argumento y una historia paralela a los distintos niveles de la partida. Otro elemento que lo hace único es la interacción que ofrece con Facebook, permitiendo publicar los resultados en el "muro" de cada jugador. 
Así pues en este webcast tendremos la posibilidad de conocer este caso de éxito y la forma en que se ha organizado Nivel 21 para conseguir grandes resultados con muy pocos recursos.

Recordad que para asistir al evento hay que registrarse previamente en este enlace.

Descripción:
Tecnicas de gestión de proyectos modernas aplicadas al desarrollo de juegos con XNA. Consejos y herramientas para gestionar un equipo amateur de desarrolladores, orientado a producir el mejor juego posible con muy pocos recursos. Prácticas para ayudarte a enforcar tus esfuerzos en los aspectos más relevantes de la producción. Conoce los detalles de la producción de "Rotor'scope, El secreto de la energía infinita" (Segundo Premio del concurso Dream Build Play 2009) de mano de uno de sus creadores.

Ponente:
Mauricio García Serrano

Links de interés:
http://uoc.dotnetclubs.com
http://www.codeplex.com/XNACommunity

http://www.nivel21.net/

[OT] XBOX Live E V O L U C I O N A

Sí, EVOLUCIONA, en mayúsculas, porque la última actualización viene cargada de novedades interesantes, con la incorporación de las redes sociales más importantes al servicio: twitter y facebook. Además podrán verse películas en streaming en alta definición con sonido 5.1. La actualización será obligatoria para los usuarios conectados al servicio XBOX Live, y se producirá el próximo 17 de noviembre. Este es un pequeño resumen de las novedades que os comento:

  • Ya puedes tweetear desde el sofá de tu casa, sin tener que soltar los mandos de la XBOX ;-)
  • No pierdas contacto con tus amigos ni siquiera mientras juegas! Ahora podrás actualizar tu estado directamente desde la consola, enviando imágenes de los juegos
  • La descarga de películas en streaming parece ser que va a ser el futuro... además de ver en tu casa pelis en alta definición, podrás hacerlo en Zune

Para más información, podéis visitar este enlace.

 

Posted: 15/11/2009 10:59 por Jesús Bosch | con 3 comment(s)
Archivado en:
[XNA] Chat de XNA

¿Tienes dudas de algún desarrollo y no encuentras respuestas en los foros? ¿O sencillamente tienes ganas de intercambiar conocimientos con tus iguales? Pues los programadores de XNA estamos de suerte. Existe un nuevo chat -muy activo por cierto- para la gente a la que nos gusta esta plataforma de desarrollo de videojuegos.

Para chatear no necesitas descargar ningún software, todo se hace online, así que perfecto, ¿no os parece?

Acceder a la web de Chat de XNA: xnachat.com

Posted: 14/11/2009 18:10 por Jesús Bosch | con no comments
Archivado en:
[webcast] Materiales webcast XNA

Tras un webcast... los materiales, así es que aquí os dejo el código con los ejemplos que enseñé y la PPT de la charla que di hace un par de días de XNA. Comentar que algunos de estos ejemplos están explicados en este blog, o en mi blog anterior. Hubo ciertos problemas con el audio al principio de la charla... así que si a álguien le quedó alguna duda puede contactarme en cualquier momento. Aunque cuando tenga tiempo prometo que intentaré repetir el webcast.

Aquí os dejo los materiales:

Aprovecho para recordaros que la próxima semana tenemos otro interesante webcast de XNA, presentado por Rodrigo Diaz de la Universidad de Alicante. Así que recomiendo todo aquel que como yo sea un adicto a XNA. Espero veros por allí :-)

Posted: 13/11/2009 18:23 por Jesús Bosch | con 4 comment(s) |
Archivado en: ,,,
Más artículos Página siguiente >