Ejemplo XNA parte 3 – Interactividad con el Jugador

Ya contamos con la estructura básica de nuestro juego con el Contenido Gráfico, una clase Jugador, donde posee los atributos necesarios como la vida de la aeronave, la puntuación acumulada, despliegue del elemento en la escena, entre otros. El siguiente paso para nuestro juego de ejemplo será incluir la interacción del usuario.

En la clase Game1.cs

Agregaremos tres nuevos atributos a la clase principal de nuestro juego. Anéxalas debajo de la declaración Jugador jugador.

KeyboardState KeyboardActual;
KeyboardState KeyboardPrevio;
float jugadorVel;

En Initialize, asignaremos un valor arbitrario para la velocidad de desplazamiento de la nave:

protected override void Initialize()
{
	jugador = new Jugador();
	jugadorVel = 8.0f;

	base.Initialize();
}

Ahora deberás agregar un método UpdateJugador, donde este irá chequeando si alguna de las teclas de dirección del teclado ha sido presionada, y en caso que lo estén, se suman o restan el valor de velocidad de la nave para desplazarla a lo largo de la pantalla. Al final de estas condiciones, usando el método Clamp, validamos que la nave del jugador permanezca dentro de las dimensiones de la pantalla. Pega este método antes del método Update.

private void UpdateJugador(GameTime gameTime)
{
	if (KeyboardActual.IsKeyDown(Keys.Left))
	{
		jugador.Position.X -= jugadorVel;
	}
	if (KeyboardActual.IsKeyDown(Keys.Right))
	{
		jugador.Position.X += jugadorVel;
	}
	if (KeyboardActual.IsKeyDown(Keys.Up))
	{
		jugador.Position.Y -= jugadorVel;
	}
	if (KeyboardActual.IsKeyDown(Keys.Down))
	{
		jugador.Position.Y += jugadorVel;
	}
	jugador.Position.X = MathHelper.Clamp(jugador.Position.X, 0, 
		GraphicsDevice.Viewport.Width - jugador.Width);
	jugador.Position.Y = MathHelper.Clamp(jugador.Position.Y, 0, 
		GraphicsDevice.Viewport.Height - jugador.Height);
}

Por último, evidentemente debemos invocar este método constantemente dentro del Game Loop. Eso se hace llamando UpdateJugador dentro del método Update, y previamente asignar los estados de teclado (KeyboardPrevio y KeyboardActual).

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

	KeyboardPrevio = KeyboardActual;
	KeyboardActual = Keyboard.GetState();
	UpdateJugador(gameTime);

	base.Update(gameTime);
}

En este punto, el juego ya cuenta con una clase Jugador donde se despliega el elemento en escena, y además puede ser controlado con las flechas de dirección del teclado.

Ya con la interactividad del juego es un gran avance, sin embargo, todavía nos falta agregarle el factor diversión. No te preocupes que todo esto se ira implementando mas adelante y sin mayor dificultad. Puedes descargarte el proyecto en esta fase en el siguiente enlace:

Proyecto Shooter Parte 3

Interacción en XNA para Windows Phone: Usando el Acelerómetro

El acelerómetro es un sensor que se encuentran en la mayoría de dispositivos móviles de hoy en día. Básicamente, este sensor constantemente mide el cambio de las aceleraciones asociadas con el fenómeno de peso experimentada por una masa de prueba que se encuentra en el marco de referencia del dispositivo. En otras palabras, es un sensor capaz de detectar el mínimo movimiento de posición del dispositivo en cualquiera de sus tres ejes. Para el caso particular de Windows Phones, es importante que tengas presente la convención de los ejes para este tipo de dispositivos:

Es importante tener en cuenta la convención de ejes de coordenadas del dispositivos con el que queremos desarrollar una aplicación que involucre utilizar el acelerómetro. Otra facilidad que nos ofrece el emulador de Windows Phone es la funcionalidad de simular el cambio de orientación del teléfono, ideal cuando queremos hacer pruebas de nuestra aplicación utilizando el acelerómetro para aquellos desarrolladores que no cuentan con el teléfono físico.

Puedes establecer la posición inicial del teléfono (modo retrato levantado, modo horizontal levantado, modo retrato acostado y modo horizontal acostado), y en base a esa posición deberás implementar tu aplicación. Ahora prosigamos a implementar un ejemplo sencillo donde una pequeña imagen que se desplazara de acuerdo a la orientación a la que se encuentre el dispositivo.

Ejemplo de una aplicación utilizando el acelerómetro

Abre Visual Studio 2010 y crea un proyecto tipo Windows Phone Game (4.0), y nómbralo «AcelerometroXNA». Ahora debemos agregar una referencia para utilizar el Acelerómetro. Dale clic-derecho a la carpeta Referencias y dale clic a «agregar Referencia», y busca la librería .NET «Microsoft.Devices.Sensors».

Una vez agregada esa referencia, importa la librería en la clase Game1.cs:

using Microsoft.Devices.Sensors;

Ahora, nuevamente agreguemos una imagen al Content de nuestro proyecto. En este ejemplo usaremos la siguiente imagen:

Dale clic-derecho a AcelerometroXNAContent, y selecciona «agregar->ítem existente», y selecciona la imagen que descargaste previamente.

Regresando a nuestra Game1.cs, en el constructor Game1, reemplázalo por este:

Accelerometer accelerometer;
Texture2D circuloTex;
Vector2 circuloPos;
Vector2 circuloVel;

En el constructor de Game1.cs, debemos establecer explícitamente las dimensiones de la pantalla, a modo que este evite de rotar automáticamente independientemente a como manipulemos el dispositivo.

public Game1()
{
	graphics = new GraphicsDeviceManager(this);
	graphics.PreferredBackBufferHeight = 800;
	graphics.PreferredBackBufferWidth = 480;
	Content.RootDirectory = "Content";
	TargetElapsedTime = TimeSpan.FromTicks(333333);
	InactiveSleepTime = TimeSpan.FromSeconds(1);
}

En el método Initialize, inicializamos la posición de nuestra imagen en el centro de la pantalla, instanciamos nuestra clase acelerómetro, y le agregamos un manejador de evento (AccelReadingChanged) que se disparara cada vez que el sensor detecte un cambio de valor de aceleración en cualquiera de sus tres ejes; y por último, hacemos Start al acelerómetro para que comience a recibir datos del sensor.

protected override void Initialize()
{
	circuloPos = new Vector2(
		graphics.PreferredBackBufferWidth / 2, 
		graphics.PreferredBackBufferHeight / 2);
	accelerometer = new Accelerometer();
	accelerometer.ReadingChanged += new EventHandler
		<AccelerometerReadingEventArgs>(AccelReadingChanged);
	accelerometer.Start();
	base.Initialize();
}

Ahora proseguimos a cargar nuestra imagen de marte a nuestra variable de textura circuloTex. Esto se realiza en el método LoadContent.

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

Algo muy importante que debemos hacer en el método UnloadContent particularmente en este ejemplo. Debemos liberar el recurso del acelerómetro cuando finalice la ejecución de la aplicación. Esto se hace invocando al método Stop de nuestro objeto accelerometer. Luego hacemos Unload a nuestro contenido para liberar el contenido grafico cargado a memoria.

protected override void UnloadContent()
{
	accelerometer.Stop();
	Content.Unload();
}

En el método Initialize habíamos declarado un método manejador de evento del acelerómetro llamado AccelReadingChanged. He aquí dicho método. Puedes observar que al circuloVel se le suman los valores detectados por el sensor, y estos a su vez son sumados a la posición de nuestra elemento grafico. Solo estamos trabajando con el eje X e Y, lo que significa que la posición inicial del dispositivo es horizontal, con la orientación de pantalla modo Landscape.

void AccelReadingChanged(object sender, AccelerometerReadingEventArgs e)
{
	circuloVel.X += (float)e.X;
	circuloVel.Y -= (float)e.Y;
	circuloPos += circuloVel;
}

En cuanto al método Update, que debemos hacer? Obviamente asegurarnos que nuestro planeta marte no se salga de los bordes de la pantalla. Esto es cuidando que la posición de nuestra imagen no sobrepase las dimensiones de nuestro viewport. Esto se hace con las siguientes instrucciones:

Viewport viewport = graphics.GraphicsDevice.Viewport;
if (circuloPos.X < 0) 
{ 
	circuloPos.X = 0; 
	circuloVel.X = 0; 
} 
else if (circuloPos.X > viewport.Width - circuloTex.Width)
{
	circuloPos.X = viewport.Width - circuloTex.Width;
	circuloVel.X = 0;
}
if (circuloPos.Y < 0) 
{ 
	circuloPos.Y = 0; 
	circuloVel.Y = 0; 
} 
else if (circuloPos.Y > viewport.Height - circuloTex.Height)
{
	circuloPos.Y = viewport.Height - circuloTex.Height;
	circuloVel.Y = 0;
}

Finalmente, llegamos al método Draw, donde simplemente desplegamos nuestra imagen en la posición vinculada al cambio de valores que se encuentre recibiendo el acelerómetro.

protected override void Draw(GameTime gameTime)
{
	GraphicsDevice.Clear(Color.CornflowerBlue);
	spriteBatch.Begin();
	spriteBatch.Draw(circuloTex, circuloPos, Color.White);
	spriteBatch.End();
	base.Draw(gameTime);
}

Ya el proyecto listo, proseguimos a armar nuestra solución y ejecutamos. Una vez que se ejecute el emulador, despliega el panel de herramientas adicionales, en la sección del acelerómetro. Ajusta la orientación inicial a «Landscape Flat», y dale clic a la esfera roja del emulador y trasládala hacia diversas direcciones para que observes como la imagen de marte se desplaza por la pantalla de acuerdo a la dirección de orientación del dispositivo.

De esta forma se trabaja con el Acelerómetro para Windows Phone utilizando el Framework XNA. Si tu proyecto presenta problemas de armar la solución, puedes descargarte el ejemplo:

Proyecto Acelerometro XNA

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