Ejemplo XNA parte 8 – Implementado la acción disparar del Jugador

Ya se puede observar el progreso de nuestro juego ejemplo. Ya cuenta con elementos animados como la nave y los enemigos, un fondo que le da una profundidad y una sensación de mayor movimiento en el entorno. Por los momentos, la única forma de destruir los enemigos es estrellando la nave contra ellos. Es hora de equipar la nave con un arma para disparar proyectiles contra las minas explosivas.

Comienza agregando una nueva clase llamada Projectile.cs; y elimina las declaraciones using que trae por defecto, y agrega las siguientes:

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

Ya que estaremos trabajando con clases y metodos del framework XNA. Ahora prosigue a agregar los siguientes atributos de la clase Projectile. En los comentarios observa la importancia de cada atributo.

// Imagen del proyectil
public Texture2D Texture;

// Posicion del proyectil
public Vector2 Position;

// Estado del proyectil
public bool Active;

// Cantidad de daño del proyectil
public int Damage;

// Limite visible del juego
Viewport viewport;

// Ancho del proyectil
public int Width
{
	get { return Texture.Width; }
}

// Alto del proyectil
public int Height
{
	get { return Texture.Height; }
}

// Velocidad de desplazamiento
float projectileMoveSpeed;

Ahora agreguemoe el metodo Initialize para inicializar las propiedades de la clase. Observa que le llegan tres parametros, el viewport que son las dimensiones de la escena del juego, la textura del proyectil que en nuestro caso es un rayo laser azul, y por ultimo la posicion inicial del proyectil.

public void Initialize(Viewport viewport, 
	Texture2D texture, Vector2 position)
{
	Texture = texture;
	Position = position;
	this.viewport = viewport;
	Active = true;
	Damage = 2;
	projectileMoveSpeed = 20f;
}

Como la idea de los proyectiles es que viajen de izquierda a derecha contra las minas enemigas, en el método Update evidentemente debemos incrementar la posición con respecto al eje X de acuerdo a la velocidad establecida en el método Initialize (proyectileMoveSpeed = 20f). Por último verificamos si el proyectil se ha salido de la escena para desactivar su despliegue, con el propósito de evitar desplegar imágenes que no podremos visualizar en la escena.

public void Update()
{
	// Projectiles always move to the right
	Position.X += projectileMoveSpeed;
	// Deactivate the bullet if it goes out of screen
	if (Position.X + Texture.Width / 2 > viewport.Width)
	Active = false;
}

Finalmente para esta clase, agregamos el método Draw para visualizar un proyectil en la pantalla.

public void Draw(SpriteBatch spriteBatch)
{
	spriteBatch.Draw(Texture, Position, null, Color.White, 0f,
	new Vector2(Width / 2, Height / 2), 1f, SpriteEffects.None, 0f);
}

Ya con nuestra nueva clase Projectile lista, proseguimos a hacer unas modificaciones en la clase principal.

En la Clase Game1

Comenzamos declarando los siguientes atributos.

// Textura de un proyectil
Texture2D projectileTexture;
// Lista de proyectiles
List <Projectile>projectiles;
// Tasa de proyectiles a disparar
TimeSpan fireTime;
// Tiempo de disparo anterior
TimeSpan previousFireTime;

Nota que agregamos una lista de proyectiles. Hacemos esto porque planeamos desplegar múltiples proyectiles disparados por la nave, por ende esta estructura de dato dinámica es ideal para llevar control de cada proyectil en escena en todo momento. fireTime nos dice en cada cuanto intervalo de tiempo el jugador disparará un proyectil en escena, ya verás cómo eso funciona más adelante. En el método Initialize, al final, agrega las siguientes instrucciones:

projectiles = new List<Proyectile>();
// Un laser se dispara cada cuarto de segundo
fireTime = TimeSpan.FromSeconds(.15f);

Observas el valor de fireTime? Esto quiere decir que la nave disparará 4 láseres por segundo. Ahora, En el LoadContent, al final del método, proseguimos a cargar la textura del láser, con la siguiente instrucción.

projectileTexture = Content.Load<Texture2D>("laser");

Como cuando trabajamos con el despliegue de enemigos, debemos agregar un método para AddProjectile, para instanciar y agregar nuevos proyectiles en la lista, inicializándolos con el viewport, su textura y su posición inicial.

private void AddProjectile(Vector2 position)
{
	Projectile projectile = new Projectile(); 
	projectile.Initialize(GraphicsDevice.Viewport,
	projectileTexture,position); 
	projectiles.Add(projectile);
}

Ahora debemos buscar donde invocar este método. Ya que el jugador es el único elemento que estará disparando rayos láser, tiene sentido ir al método UpdatePlayer, y agregar las siguientes instrucciones al final:

// Disparar bajo el valor de fireTime
if (gameTime.TotalGameTime - previousFireTime > fireTime)
{
	// Reiniciamos nuestro tiempo actual
	previousFireTime = gameTime.TotalGameTime;
	// Agregamos el proyectil al frente de la nave
	AddProjectile(player.Position + new Vector2(player.Width / 2, 0));
}

Aquí estamos agregando nuevos proyectiles en la cola, y disparando a la tasa del valor de fireTime. Ahora necesitamos actualizar las posiciones de cada proyectil en la escena. Como ya hicimos antes con los enemigos, debemos agregar un nuevo método llamado UpdateProjectiles y se verá de la siguiente manera:

private void UpdateProjectiles()
{
	// Actualizar los Proyectiles
	for (int i = projectiles.Count - 1; i >= 0; i--) 
	{
		projectiles[i].Update();
		if (projectiles[i].Active == false)
		{
			projectiles.RemoveAt(i);
		} 
	}
}

Observa que se invoca el método Update por cada proyectil en la escena, donde estos se desplazarán de izquierda a derecha a una velocidad uniforme, y cuando Active se encuentre en false, son removidos de la lista de proyectiles. En cuanto al método Update, proseguimos a invocar UpdateProjectiles al final:

// Actualizar proyectiles
UpdateProjectiles();

Hasta este punto los proyectiles se dibujan, se mueven, pero no colisionan con los enemigos. Dirígete al método UpdateCollision y agrega las siguientes intrucciones al final:

// Colision entre Proyectiles vs Enemigos
for (int i = 0; i < projectiles.Count; i++)
{
	for (int j = 0; j < enemies.Count; j++)
	{
		// Creamos los rectangulos para validar si hay colision
		rectangle1 = new Rectangle(
			(int)projectiles[i].Position.X - 
			projectiles[i].Width / 2,
			(int)projectiles[i].Position.Y - 
			projectiles[i].Height / 2,
			projectiles[i].Width, 
			projectiles[i].Height);

		rectangle2 = new Rectangle(
			(int)enemies[j].Position.X - 
			enemies[j].Width / 2,
			(int)enemies[j].Position.Y - 
			enemies[j].Height / 2,
			enemies[j].Width, 
			enemies[j].Height);

		// Determinamos si se intersectan
		if (rectangle1.Intersects(rectangle2))
		{
			enemies[j].Health -= projectiles[i].Damage;
			projectiles[i].Active = false;
		}
	}
}

Entiendes la lógica? Simplemente se está creando un rectángulo por cada proyectil, y se crea un rectángulo por cada enemigo visible en esa iteración (para capturar su posición en ese instante de tiempo). Luego se verifica si algún rectángulo enemigo se intersecta con el rectángulo del proyectil, y en caso afirmativo, se le resta vida al enemigo colisionado, y se desactiva el proyectil para que sea removido de la lista.

Finalmente, implementamos la logica para desplegar los proyectiles en escena. Vamos al metodo Draw, y debajo de Jugador.Draw(), inserta las siguientes instrucciones:

for (int i = 0; i < projectiles.Count; i++)
{
	projectiles[i].Draw(spriteBatch);
}

Al ejecutar nuestro juego se vera algo así:

Observa la colisión de los proyectiles contra los enemigos, pero veras que solo desaparecen cuando son destruidos. En la siguiente parte de este juego ejemplo haremos que las minas muestren un efecto de explosión cuando son destruidas por el jugador. Si estas teniendo problemas armando la solución, puedes descargarte el proyecto haciendo clic en el siguiente enlace:

Proyecto Shooter Parte 8

Despliegue de sprites animados 2D

En el capitulo anterior se explicó la manera más directa de desplegar objetos en la escena de nuestro juego. Sin embargo, estos elementos estáticos resultan aburridos y monótonos para cualquier juego que estemos trabajando. En este capitulo te voy a explicar como hacer sprites animados. Abre Visual Studio 2010, crea un nuevo proyecto de tipo Windows Game (4.0). En el Content, descarga la siguiente imagen y agrégala al Content de tu proyecto:

Ahora en el proyecto, agrega una nueva clase y nómbrala «Animation». En esta clase implementaremos la mecánica necesaria para desplegar sprites animados.

Dinámica de animación

En principio contamos de una tira de imágenes que representan una animación. Lo que queremos implementaremos es una función capaz de desplegar una sola imagen, y trasladando la imagen, desplegamos la siguiente imagen consecutiva, y así sucesivamente, dándonos la ilusión de una imagen animada, como el efecto StopMotion.

En la clase Animation

Para esta clase, primero debemos agregar las siguientes librerías fundamentales de XNA.

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

Ahora agregaremos los siguientes atributos:

// La imagen animada representada por un grupo de imagenes
Texture2D spriteStrip;

// Valor para escalar el sprite
float scale;

// Tiempo desde la ultima vez que se actualizo la imagen
int elapsedTime;

// Tiempo de despliegue por imagen
int frameTime;

// Numero de imagenes que conforman la animacion
int frameCount;

// Indice de la imagen actual
int currentFrame;

// Color de la imagen a desplegar
Color color;

// El area de la imagen que vamos a desplegar
Rectangle sourceRect = new Rectangle();

// El area donde queremos desplegar la imagen
Rectangle destinationRect = new Rectangle();

// Ancho de la una imagen
public int FrameWidth;

// Alto de una imagen
public int FrameHeight;

// Estado de la animacion
public bool Active;

// Repetir animacion
public bool Looping;

// Posicion del sprite
public Vector2 Position;

Para esta clase, utilizara tres métodos muy importantes: InitializeUpdate y Draw. Para el método Initialize, evidentemente inicializaremos todos los atributos para luego desplegar la imagen. Observa que se le pasan la mayoría de los valores por parámetros, la idea es para mantener esta clase lo mas genérica posible, a modo de re-utilizarla para cargar múltiples sprites con diferentes imágenes y propiedades.

public void Initialize(Texture2D texture, Vector2 position,
	int frameWidth, int frameHeight, int frameCount,
	int frametime, Color color, float scale, bool looping)
{
	// Mantener copias locales de los valores pasados
	this.color = color;
	this.FrameWidth = frameWidth;
	this.FrameHeight = frameHeight;
	this.frameCount = frameCount;
	this.frameTime = frametime;
	this.scale = scale;

	Looping = looping;
	Position = position;
	spriteStrip = texture;

	// Hacer reset a los tiempos
	elapsedTime = 0;
	currentFrame = 0;

	// Activar la animacion por defecto
	Active = true;
}

En cuanto al método Update, como ya se explicó la mecánica para animar sprites, aquí se implementa la lógica para desplegar la tira de imágenes, mostrándola una a una para dar la sensación de movimiento de los sprites. La lógica del método Update es el siguiente:

public void Update(GameTime gameTime)
{
	// No actualizar si la imagen esta desactivada
	if (Active == false) 
		return;

	// Actualizar tiempo transcurrido
	elapsedTime += (int)gameTime.ElapsedGameTime.TotalMilliseconds;

	// Si elapsedTime es mayor que frame time
	// debemos cambiar de imagen
	if (elapsedTime > frameTime)
	{
		// Movemos a la siguiente imagen
		currentFrame++;
		// Si currentFrame es igual al frameCount 
		// hacemos reset currentFrame a cero
		if (currentFrame == frameCount)
		{
			currentFrame = 0;
			// Si no queremos repetir la animacion
			// asignamos Active a falso
			if (Looping == false)
				Active = false;
		}
		// Reiniciamos elapsedTime a cero
		elapsedTime = 0;
	}
	// Tomamos la imagen correcta multiplicando el currentFrame 
	// por el ancho de la imagen
	sourceRect = new Rectangle(
		currentFrame * FrameWidth, 0, FrameWidth, FrameHeight);

	// Actualizamos la posicion de la imagen en caso que esta
	// se desplace por la pantalla
	destinationRect = new Rectangle(
		(int)Position.X - (int)(FrameWidth * scale) / 2,
		(int)Position.Y - (int)(FrameHeight * scale) / 2,
		(int)(FrameWidth * scale),
		(int)(FrameHeight * scale));
}

Finalmente llegamos en el método Draw, donde simplemente invocamos el método spriteBatch.Draw SIEMPRE y cuando active este en verdadero. Aquí esta el método Draw:

public void Draw(SpriteBatch spriteBatch)
{
    if (Active)
    {
        spriteBatch.Draw(spriteStrip, destinationRect, sourceRect, color);
    }
}

Este es todo el código necesario para nuestra clase Animacion. Ahora solo debemos instanciarla, inicializarla y llamarla para desplegarla en escena y e invocar su método Update para que refresque las imágenes para lograr la animación del sprite.

En la clase Game1

Para nuestra clase principal, comenzaremos agregando los siguientes atributos:

Animation playerAnimation;
Vector2 spritePos;

Proseguimos a dirigirnos al método LoadContent, donde cargaremos la imagen del Content a la variable playerTexture e instanciar la posición inicial del sprite, y se la enviamos por parámetros al método Initialize a nuestro objeto playerAnimation:

protected override void LoadContent()
{
	spriteBatch = new SpriteBatch(GraphicsDevice);

	playerAnimation = new Animation();
	Texture2D playerTexture = Content.Load<Texture2D>("Ken");

	spritePos = new Vector2(
		GraphicsDevice.Viewport.TitleSafeArea.X +
		GraphicsDevice.Viewport.TitleSafeArea.Width / 2,
		GraphicsDevice.Viewport.TitleSafeArea.Y +
		GraphicsDevice.Viewport.TitleSafeArea.Height / 2);

	playerAnimation.Initialize(playerTexture,  
		spritePos, 106, 110, 6, 80, Color.White, 1f, true);
}

Ahora en el método Update, basta con solo invocar el método Update de nuestro objeto playerAnimation:

playerAnimation.Update(gameTime);

Y Finalmente, en el método Draw, invocamos el método Draw de nuestro objeto playerAnimation. Recuerda que debes encapsular esta instrucción con los metodos spriteBatch.Begin(); y spriteBatch.End(); de lo contrario, no veras ningún elemento desplegado en escena.

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

Ya en este punto, queda armar la solucion y esperar que se ejecute tu aplicacion con una animacion de Ken corriendo. Te anexo una captura de la aplicacion:

Experimenta las propiedades de la clase Animacion, y analiza los resultados. Qué ocurre si le aumentas el currentTime? Qué ocurre si le aumentas el scale? Es importante que estudies el comportamiento de esta clase para que tengas un mayor control y entendimiento sobre sprites animados. Este es un camino para animar sprites, pero puede haber muchas otras formas para hacerlo.

Si presentas problemas armando tu solución, puedes descargar el proyecto final en el siguiente enlace:

Proyecto AnimacionXNA

Ejemplo XNA parte 2 – Creación de la Clase Jugador

Haz un clic derecho sobre el proyecto y agrega una nueva clase llamada «Jugador», y agrega los métodos Initialize, Update y Draw. Deberás importar las librerías de XNA.

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Shooter
{
	class Jugador
	{
		public void Initialize()
		{
		}

		public void Update()
		{
		}

		public void Draw()
		{
		}
	}
}

Esta es la estructura básica de nuestra clase Jugador, que funcionará para desplegar el elemento que controlará el usuario, que en nuestro caso es la aeronave. Ahora agrega los siguientes atributos (observa la importancia de cada uno que se encuentran comentados)

// Animacion representando al jugador
public Texture2D PlayerTexture;

// Posicion del jugador
public Vector2 Position;

// Estado del jugador
public bool Active;

// Cantidad de vida del jugador
public int Health;

// Obtener el ancho del jugador
public int Width
{
	get { return PlayerTexture.Width; }
}

// Obtener el alto del jugador
public int Height
{
	get { return PlayerTexture.Height; }
}

Estos son algunos atributos fundamentales para nuestra clase jugador, pero obviamente se pueden agregar mas dependiendo del control que queramos tener sobre este elemento. Ahora reemplaza el método Initialize (de la clase Jugador) con lo siguiente:

public void Initialize(Texture2D texture, Vector2 position)
{
	PlayerTexture = texture; 
	// Asignar la posicion del jugador
	Position = position;
	// Activar el jugador
	Active = true;
	// Inicializar la vida del jugador
	Health = 100;
}

Como se puede ver claramente, lo que hace el metodo Initialize es establecer las propiedades iniciales de nuestra clase Jugador. Ahora reemplaza el metodo Draw con el siguiente:

public void Draw(SpriteBatch spriteBatch)
{ 
	spriteBatch.Draw(PlayerTexture, Position, null, 
		Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0f);
}

Ya con la clase Jugador con sus atributos y funciones listas, pasaremos a la clase principal para instanciar un objeto Jugador.

En la clase Game1.cs

Ya que tenemos todo preparada la clase Jugador, debemos instanciarla, inicializarla y por último, invocar su método Draw desde esta clase principal para desplegar la nave en la pantalla. Ve al inicio de esta clase, y debajo de la declaración del atributo SpriteBatch spriteBatch; agrega nuestra variable tipo Jugador.

Jugador jugador;

Y ahora en el método Initialize, instanciamos nuestra clase:

jugador = new Jugador();

Siguiente, debemos cargar la textura de nuestra nave que se encuentra en el Content de nuestro proyecto. En el método LoadContent, agrega las siguientes líneas:

// Load the player resources 
Vector2 playerPosition = new Vector2(
	GraphicsDevice.Viewport.TitleSafeArea.X,
	GraphicsDevice.Viewport.TitleSafeArea.Y + 
	GraphicsDevice.Viewport.TitleSafeArea.Height / 2);
jugador.Initialize(Content.Load<Texture2D>("Imagenes/nave"), playerPosition);

Ya que tenemos nuestro objeto Jugador instacianciado, y cargado, ve al metodo Draw y agrega las siguientes instrucciones:

spriteBatch.Begin();
jugador.Draw(spriteBatch);
spriteBatch.End();

Ahora finalmente compila el proyecto, y ejecútalo. Si todo funciona correctamente, verás algo como esto:

Si tu proyecto presenta errores y no encuentra como solucionarlos, no entres en pánico, puedes descargar el proyecto de acá en su estado final de este tutorial, simplemente da clic al siguiente enlace:

Proyecto Shooter Parte 2

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

Despliegues de Sprites en 2D

Bien, ya visto en articulos anteriores todo el basamento teórico de como funciona el Framework XNA, las versiones que han salido desde su lanzamiento en el 2007, el soporte para las diversas plataformas de Microsoft (Windows PC, Xbox 360 y Windows Phone), el funcionamiento de XNA y por último, la estructura de un proyecto de un Windows Game XNA en Visual Studio, es hora que empecemos a codificar y dibujar elementos.

Paso 1. Crear el proyecto

Debes abrir Visual Studio 2010 con XNA Game Studio 4 previamente instalado, y crear un proyecto Windows Game (4) como se mostró en el artículo anterior.

Paso 2. Agregar una imagen a nuestro Content

Ahora debemos agregar una carpeta en el Content donde colocaremos nuestras imágenes. No es requerido crear un directorio, pero lo recomiendo para mantener nuestro contenido gráfico organizado. Simplemente da un clic-derecho en tu proyecto Content, le das clic a agregar->nueva carpeta, y lo nombraremos «Imagenes».

Para agregar una imagen (que la pueden encontrar aqui para descargar), dale clic-derecho a la carpeta «Imagenes» ya creada, luego clic en agregar->item existente. Te saldrá un explorador de archivos, para que busques el archivo de imagen que deseas agregar a tu proyecto. Selecciona la imagen que descargaste previamente (smiley.png), y le das clic a «Agregar»).

Paso 3. Dibujar el sprite en la Escena

Ya que tenemos nuestra imagen en el Content de nuestro proyecto, debemos cargarla y desplegarla escribiendo código. Lógicamente para desplegar esta imagen, dependemos lógicamente de dos cosas: Posición y Textura. Para eso, agrega las siguientes dos variables dentro de tu clase principal (Game1), debajo de spriteBatch. El código se vería de la siguiente manera:

Vector2 es un tipo de datos que posee dos campos float x,y; a modo de trabajar con coordenadas de dos dimensiones. Ininializa posicion en el método Initialize:

Ahora procedemos a cargar la imagen a nuestro juego. Esto se hace en el método LoadContent. El código quedaría así:

Puedes observar que se instancia la variable spriteBatch (el cual puedes verlo por los momentos como el pincel encargado de pintar todos los elementos en la escena de nuestro juego). También observa como se carga una textura2D con el método Load. Toma en cuenta el string que pasamos como parámetro; es la ruta del elemento que queremos cargar. Por esto, es importante colocar en qué directorio se encuentra si esta organizado de esta manera.

Paso 4. Desplegar nuestro sprite en la escena

Recapitulando, hemos agregado nuestra imagen archivo al contenido de nuestro proyecto; hemos agregado una variable para la posición donde desplegaremos nuestro sprite, y declaramos una variable Texture2D, donde realizamos la carga de nuestra imagen del contenido a la aplicación. Ahora, sin más preámbulos, dibujemos nuestro sprite. Esto se implementa en el método Draw.

Para pintar nuestro sprite, debemos utilizar nuestra variables spriteBatch, ya que este es el encargado de dibujar los elementos en la escena como ya mencione a priori. Todos los elementos que vayamos a dibujar se hacen mediante su método Draw(), y estos deben estar encerrados dentro de los métodos spriteBatch.Begin() y spriteBatch.End(). Muy importante estos dos métodos, porque estamos avisando a nuestra aplicación que vamos a pintar elementos, y cuando terminemos, invocamos el método End(). En nuestro caso, nuestro código se vera así:

Fíjate el método spriteBatch.Draw(). Solo estamos pasando la textura que deseamos desplegar, la posición, y el color que queremos que sea desplegado. Si colocamos Blanco, se mostraran los colores originales de la imagen. Cualquier otro color modificara los colores de nuestro sprite.

Finalmente, al ejecutar nuestra aplicación, tendrás un resultado como este:

Sencillo, no crees? Esta es la manera mas elemental para desplegar un sprite en nuestro juego. El método Draw que utilizamos es el mas básico disponible, ya que este método cuenta con 7 formas distintas de invocar con diversos parámetros, incluyendo efectos, manejo de rectángulos para dibujar ciertas áreas, etc. Para proyectos más complejos, se trabajan con clases donde encapsulan estas propiedades (textura, posición), y se le agregan mas propiedades para ser mas flexibles ante transformaciones y efectos.

Estructura de un proyecto XNA

Para crear un proyecto XNA, debemos abrir Visual Studio 2010 con el XNA Game Studio 4.0 previamente instalado. Da un clic en Archivo, Nuevo Proyecto, y ve a la categoría de plantillas «XNA Game Studio», y selecciona la plantilla Windows Game (4.0). Escribe el nombre de proyecto deseado y le das click en  aceptar.

Una vez creado el proyecto, verás la clase principal del proyecto que por defecto se llama Game1. En el Solution Explorer, veras la siguiente estructura de carpetas.

Proyecto WindowsGame1

En esta sección de la solución es donde se desarrolla toda la lógica del juego. La clase principal es la llamada Class1, donde se encuentra bien definidos los métodos principales a implementar acorde al funcionamiento del framework XNA. Existe otra clase estática llamada Program.cs, donde aquí en realidad es el que invoca la Clase1 para ejecutarla; sin embargo, tu labor es implementar tu juego es en la clase Class1.

También veras un archivo llamado «Game.ico», donde este es un pequeño icono de 32×32 pixeles que se coloca en la esquina superior izquierda de la ventana de nuestro juego al momento de ejecutar nuestra aplicación. Este icono también se mostrara si lo anclas a la barra de inicio.

Entre otros elementos dentro de este proyecto, se encuentra el directorio “Properties”, donde se encuentra el archivo “AssemblyInfo.cs”, que es el archivo configuración de ensamblado de nuestro proyecto. Al abrirlo, veras que contiene toda la información acerca de la versión de la aplicación, el Titulo del juego, producto, descripción, año, etc. También se encuentra el directorio «References», donde en esta se encuentra referencias a las librerías fundamentales requeridas para el funcionamiento de este proyecto. Si deseas trabajar con librerías externas encontradas en la web (Como trabajar con el Kinect, o librerias de físicas, etc.), con descargarlas y hacerles referencia, ya se encuentran disponibles para utilizarlas en tu juego.

En este punto, te sugiero que trabajes con directorios de clases, a modo de trabajar un proyecto de manera organizada por grandes módulos esenciales, como física, sonido, gráficos, interacción entrada/salida, etc.

Proyecto WindowsGame1Content

Para este proyecto de tipo Windows Game Library (4.0) que se genera automáticamente en la solución al momento que se crea un Windows Game (4.0), es donde se coloca todo el contenido gráfico audiovisual del juego. Se recomienda que organices el contenido en directorios, para imágenes, archivos de configuración, sonidos, videos, música de fondo, etc. Esta sección ya se encuentra referenciada por el proyecto principal (que se puede ver dentro del directorio «Content References»).

Mecanismo del Framework XNA

A continuación se muestra una figura de la forma como funciona el framework XNA a nivel de implementación. Es de suma importancia saber el orden de los métodos que son invocados cómo desarrollamos nuestros juegos. Sin mas que agregar, se muestra el diagrama, y la explicación de cada método en el orden de ejecución para el momento que se inicia un juego hasta el momento que finaliza.

Método Initialize

El método Initialize es usado para inicializar variables y otros objetos asociados con el objeto Game1. Los objetos del dispositivo grafico será inicializados en este punto y pueden ser usados en el métodos Initialize para ayudarte a inicializar otros objetos que dependen en la configuración. Utilizarás este método para inicializar valores de puntuación y otros valores afines.

Método LoadContent

El método LoadContent es invocado después del método Initialize, de la misma forma para el caso que el contenido grafico debe ser recargado (Por ejemplo cuando el dispositivo grafico debe ser reiniciado debido a que el jugador ha cambiado la configuración grafica del juego, o algo por el estilo). El método LoadContent es donde se carga todos los gráficos y otro contenido requerido por el juego, incluyendo imágenes, modelos, sonidos, etc.

Game Loop (Método Update y Metodo Draw)

Despues que culmina el método LoadContent, el juego entra en un estado conocido como Game Loop, o bucle de juego.  Casi todos los juegos entran en algún tipo de bucle de juego, independientemente si están escritos en XNA o no. Esta área de código difiere del típico entorno de programación de juegos, y para algunos desarrolladores les puede tomar algo de tiempo acostumbrarse.

En esencia, un Game Loop consiste en una serie de métodos que son invocados una y otra vez hasta que el juego finaliza. En XNA, el Game Loop consiste en dos métodos: Update y Draw. Por ahora, puedes pensar en el Game Loop en estos términos: toda la lógica que afecta el juego actual se encontrará en el método Update o el método Draw. El método Draw es típicamente usado, obviamente, para dibujar elementos. Procura implementar lo mínimo que puedas en esta área excepto para desplegar elementos de tu escena. Todo lo demás que sea necesario para la ejecución adecuada de tu juego (que eventualmente involucra el mover objetos, chequear colisiones, actualizar puntuaciones, chequear la condición fin de juego, etc.) se encontrará en el método Update.

Método UnloadContent

Al punto dentro del Game Loop donde se llegue a una condición de finalizar el Juego, el bucle se termina, y se invoca automáticamente el método UnloadContent. Este método es usado para liberar cualquier contenido cargado previamente en el método LoadContent que requiere un manejo especial de liberación. Tipicamente, XNA (como .NET) manejara la recolección de basura automáticamente, pero si has modificado la memoria en algún objeto que requiere un manejo especial, el método UnloadContent es donde implementaras la lógica de liberación de contenido de la memoria.

Que es XNA?

Microsoft XNA es un conjunto de herramientas con un entorno de ejecución provisto por Microsoft que facilita el desarrollo y manejo de videojuegos. XNA se enfoca de librar a los desarrolladores de juegos de escribir mucho código repetitivo pero con ligeros cambios, y traer diferentes aspectos de producción del juego en un solo sistema.

Actualmente, XNA engloba toda la sección de desarrollo de videojuegos para Microsoft, incluyendo el kit de desarrollo estándar de Xbox y XNA Game Studio.

El nombre XNA se origino de un nombre de proyecto de desarrollo, la Nueva Arquitectura de la Xbox en ingles. En lugar de ser liberado con el nombre de Xbox, se lanzo al mercado el Xbox 360, y XNA llevo el nuevo acrónimo “XNA NO es un Acrónimo”.

Versiones de XNA

XNA Game Studio Express

Fue el primer release de XNA Game Studio, para estudiantes, aficionados y desarrolladores de juegos independientes. Estaba disponible como una descarga gratuita. Express provee kits básicos para desarrollo rápido de géneros de juegos específicos, como juegos de plataforma, estrategia en tiempo real, y shooter en primera persona. Desarrolladores pueden crear juegos para Windows gratuitos con el Framework de XNA, pero para Xbox 360 se debe pagar una subscripción anual de 99$ en el XNA Creators Club.

La primera versión beta de XNA Game Estudio Express fue liberado para descarga el 30 de agosto del 2006, seguido de una segunda versión el 1ero de noviembre del mismo año. El 11 de diciembre Microsoft publicó la versión final.

El 24 de abril del 2007, Microsoft liberó una actualización conocida como el XNA Game Studio Express 1.0 Refresh.

XNA Game Studio 2.0

XNA Game Studio 2.0 fue liberado el 13 de Diciembre del 2007. Esta versión incluía la facilidad de ser utilizado en todas las versiones de Visual Studio 2005 (incluyendo la versión gratuita Edicion Express  de Visual C#),  incluyendo un API con conexión a servicios de Xbox Live en ambos Windows y Xbox 360, y mejor manejo de dispositivos.

XNA Game Studio 3.0

Esta versión salió para Visual Studio 2008 y la edición gratis Visual C# 2008 Express. XNA Game Studio 3.0 permitió la producción de juegos orientados a la plataforma Zune y agrega soporte de la comunidad de Xbox Live. Un beta de un toolset fue liberado el 30 de Octubre del 2008. Para esta versión ya soportaba C# 3.0, LINQ y muchas más versiones de Visual Studio 2008. En cuanto a nuevas funcionalidades del framework, se agregó el modo trial para hacer versiones de prueba de los juegos desarrollados, funciones de multijugador para Xbox Live como invitaciones in-game, crear juegos para las plataformas Windows, Xbox 360 y Zune.

XNA Game Studio 3.1

XNA Game Studio 3.1 fue soltado el 11 de junio del 2009. Este API incluye soporte para reproducción de video, un nuevo API de audio, el sistema de Xbox Live Party y soporte para juegos que utilicen avatares de Xbox 360.

XNA Game Studio 4.0

Anunciado y liberado inicialmente a una comunidad técnica de prueba en la Conferencia de Desarrolladores de Juegos, el 9 de marzo del 2010, y en su versión final el 16 de septiembre del mismo año. Esta versión agrego soporte a la plataforma de Windows Phone (incluyendo aceleración de hardware para 3D), perfiles de hardware, efectos configurables, estados de objetos embebidos, el cruce de plataformas, input multitouch y micrófono e incluso la integración con Visual Studio 2010.

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