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

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

 

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:

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

 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 😛

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

 

[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

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