Interacción en XNA para Windows Phone: Capturas usando TouchCollection

A pesar de la comodidad que nos brinda el framework XNA para reconocer gestos de manera sencilla, a veces podemos encontrarnos en la situación que queremos tener mas control sobre el manejo de eventos en la pantalla táctil del teléfono. Es por esto que existe otra forma de realizar captura de datos de la pantalla por parte del usuario. Hagamos un ejemplo para que veas este camino de interactividad con la pantalla táctil de un Windows Phone.

Ejemplo de captura de eventos táctiles

Abre Visual Studio 2010, y crea un proyecto Windows Phone Game (4.0), nómbralo «TouchXNA». Ahora para este proyecto, implementaremos una lógica para desplegar una imagen donde el usuario este «tocando» la pantalla, y además muestre las coordenadas y el ID del punto detectado.

Ahora busca cualquier imagen que deseas que no pase los 80×80 pixeles, y descárgala. En este ejemplo se usará la siguiente imagen del planeta marte.

Preparando el Content

Ahora dale clic-derecho sobre el Content del proyecto, y selecciona «agregar->ítem existente» y busca la imagen que deseas agregar. Ahora agrega un nuevo ítem en el Content, pero esta vez tipo «Sprite Font», y nómbralo «SpriteFont1»

Implementando la lógica

Regresa a la clase Game1.cs, en la región de la declaración de los atributos, agrega lo siguiente justo debajo de la línea «SpriteBatch spriteBatch;«:

SpriteFont spriteFont;
TouchCollection touchCollection;
Texture2D planetaTextura;
Vector2 planetaPosicion;
Vector2 textoPosicion;

Usaremos el spriteFont para el formato del string que imprimiremos la información del punto de contacto encontrado. planetaTextura resguarda la textura de la imagen que deseamos desplegar en el punto de contacto. planetaPosicion se utilizará para designar la posición donde queremos desplegar planetaTextura. touchCollection es de tipo TouchCollection, y funciona como una lista que almacena los puntos de contacto detectados en cada instante de tiempo.

Dirígete al método LoadContent para cargar la fuente y la textura que habíamos agregado previamente a nuestro Content del proyecto:

protected override void LoadContent()
{
	spriteBatch = new SpriteBatch(GraphicsDevice);
	planetaTextura = Content.Load<Texture2D>("planet-mars");
	spriteFont = Content.Load("SpriteFont1");
}

Ya con nuestro contenido cargado a nuestra aplicación, proseguimos a realizar el proceso de detección de puntos de contacto por parte del usuario, donde asignaremos la posición del planeta y del texto a desplegar en la pantalla. Esto se realiza en el método Update:

protected override void Update(GameTime gameTime)
{
	if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) 
		this.Exit();

	touchCollection = TouchPanel.GetState();
	if(touchCollection.Count >= 1){
		planetaPosicion.X = touchCollection[0].Position.X - planetaTextura.Width / 2;
		planetaPosicion.Y = touchCollection[0].Position.Y - planetaTextura.Height / 2;
		textoPosicion.X = touchCollection[0].Position.X + 35;
		textoPosicion.Y = touchCollection[0].Position.Y + 10;
	}
	base.Update(gameTime);
}

Puedes observar que a planetaPosicion le asignamos la posición del punto encontrado, restándole la mitad del ancho y alto para los ejes X e Y. Si no hacemos esto, donde nosotros toquemos la pantalla, la imagen se mostrará pero no centrada en el punto. Esto es porque la posición de  una imagen es con respecto a la esquina izquierda superior. Esto se puede ajustar sencillamente restándole la mitad del ancho y alto de la imagen a la posición del punto de contacto.

Ahora, en cuanto al método Draw, agrega las siguientes líneas de instrucciones:

protected override void Draw(GameTime gameTime)
{
	GraphicsDevice.Clear(Color.CornflowerBlue);
	spriteBatch.Begin();
	foreach (TouchLocation touch in touchCollection)
	{
		spriteBatch.Draw(planetaTextura, planetaPosicion, Color.White);
		spriteBatch.DrawString(spriteFont, 
			"ID: " + touch.Id.ToString() + " (" + (int)touch.Position.X +
			"," + (int)touch.Position.Y + ")", textoPosicion, Color.White);
	}
	spriteBatch.End();
	base.Draw(gameTime);
}

Ahora es momento de compilar y ejecutar tu aplicación. Si todo funciona correctamente, veras el emulador de Windows Phone con tu aplicación ejecutándose, y cuando hagas clic en la pantalla y arrastres el cursor, veras la imagen moviéndose junto a su mouse. A continuación una captura de la aplicación:

Sencillo, no crees? Unas cuantas líneas de código y puedes conseguir los puntos de contacto detectados en la pantalla táctil del Windows Phone. Si tu proyecto presenta errores de compilación, puedes descargarte el ejemplo:

Proyecto TouchXNA

Interacción en XNA para Windows Phone: Reconocimiento de Gestos

XNA posee funcionalidades innatas para reconocer los gestos más comunes con los que interactuamos normalmente con cualquier dispositivo móvil en la actualidad. Simplemente se debe habilitar el reconocimiento de gestos, y así el juego tendrá la capacidad de interpretar cualquier tipo de gesto realizado por parte del usuario. Los gestos más comunes se muestran en el siguiente diagrama.

Un Tap es el gesto cuando le damos un toque rápido en algún punto de la pantalla. Double Tap son dos toques consecutivos en un mismo punto, como hacer un doble clic. El Pinch y Stretch son el típico gesto que conocemos para hacer zoom-in y zoom-out en una foto o una imagen. El gesto Pan ocurre cuando deseamos trasladarnos por un scrollbar, o navegar por un mapa o imagen. Flick es un toque rápido con alguna dirección, lo que causa una especie de inercia a algún elemento que estemos trasladando.

A continuación implementaremos un ejemplo sencillo de reconocimiento de gestos utilizando el Framework XNA para Windows Phone.

Ejemplo de Reconocimiento de Gestos

Crea un proyecto Windows Phone Game (4.0), y nómbralo «GestosXNA», selecciona versión del sistema operativo 7.1. Haz un clic-derecho sobre el Content del proyecto, y agrega un nuevo Ítem de tipo «Sprite Font», y nómbralo «SpriteFont1».

En la clase Game1.cs, después de la declaración del atributo SpriteBatch spriteBatch; agrega los siguientes atributos:

SpriteFont spriteFont;
String message = "Realiza un gesto";
Vector2 messagePos = Vector2.Zero;
Color color = Color.Black;

Ahora, en el método Initialize, y agrega la siguiente instrucción antes de la línea base.Initialize(); y agrega lo siguiente:

TouchPanel.EnabledGestures = GestureType.Tap | GestureType.DoubleTap | 
                        GestureType.Hold | GestureType.HorizontalDrag | 
                        GestureType.VerticalDrag | GestureType.FreeDrag | 
                        GestureType.DragComplete | GestureType.Pinch | 
                        GestureType.PinchComplete | GestureType.Flick;

De esta forma, estamos habilitando cuales gestos deseamos que nuestra aplicación sea capaz de reconocer en tiempo de ejecución. En el método LoadContent, cargaremos la fuente agregada del Content, de esta manera:

protected override void LoadContent()
{
	spriteBatch = new SpriteBatch(GraphicsDevice);
	spriteFont = Content.Load<Texture2D>("SpriteFont1");
}

Ahora, en el método Update es donde en cada ciclo del Game Loop, el juego realizara una captura del estado de la pantalla táctil, registrando gestos realizados por el usuario, y los irá reconociendo en tiempo real. El método completo está implementado de la siguiente forma:

if (TouchPanel.IsGestureAvailable)
{
	GestureSample gesture = TouchPanel.ReadGesture();
	switch (gesture.GestureType)
	{
		case GestureType.Tap:
			message = "Tap";
			color = Color.Red;
			break;
		case GestureType.DoubleTap:
			message = "Doble Tap";
			color = Color.Orange;
			break;
		case GestureType.Hold:
			message = "Hold";
			color = Color.Yellow;
			break;
		case GestureType.HorizontalDrag:
			message = "Arrastre horizontal";
			color = Color.Blue;
			break;
		case GestureType.VerticalDrag:
			message = "Arrastre vertical";
			color = Color.Indigo;
			break;
		case GestureType.FreeDrag:
			message = "Arrastre libre";
			color = Color.Green;
			break;
		case GestureType.DragComplete:
			message = "Gesto arrastre completado";
			color = Color.Gold;
			break;
		case GestureType.Flick:
			message = "Flick";
			color = Color.Violet;
			break;
		case GestureType.Pinch:
			message = "Pinch";
			color = Color.Violet;
			break;
		case GestureType.PinchComplete:
			message = "Gesto pinch completado";
			color = Color.Silver;
			break;
	}
	messagePos = gesture.Position;
}

Primero se verifica si el TouchPanel tiene el reconocimiento de gestos habilitados. Luego TouchPanel.ReadGesture() devuelve un GestureSample en cada ciclo del GameLoop, que es analizado en el switch(gesture), y se detendrá en el caso correspondiente al gesto reconocido, cambiando el valor del string message, informando el gesto detectado, y finalmente, se le asigna la posición del mensaje donde ocurrió el gesto analizado.

En el método Draw, proseguimos a dibujar nuestro string:

protected override void Draw(GameTime gameTime)
{
	GraphicsDevice.Clear(Color.CornflowerBlue);
	spriteBatch.Begin();
	spriteBatch.DrawString(spriteFont, message, messagePos, color);
	spriteBatch.End();
	base.Draw(gameTime);
}

Listo! Ahora compila la solución y si todo esta correctamente codificado, veras la siguiente pantalla:

Ya con la aplicación ejecutándose en el emulador Windows Phone, realiza gestos utilizando tu mouse y verás que son reconocidos por nuestra aplicación, mostrando un mensaje sobre el gesto detectado, y en la posición donde ocurrió.

Desafortunadamente no podrás realizar gestos multitouch como el Pinch; para eso necesitarías hacer deploy del proyecto a un teléfono físico. Sin embargo, puedes realizar cualquier otro gesto habilitado. Experimenta y realiza todos los gestos disponibles.

Si tu proyecto presenta errores de compilación, puedes descargarte el ejemplo:

Proyecto GestosXNA

Diseña un sitio como este con WordPress.com
Comenzar