07 febrero 2011

Convertir el juego de SDL a XNA (1)


En este primer acercamiento, veremos las pautas básicas de cómo hacer que un personaje se mueva por la pantalla al pulsar las flechas del teclado. Posteriormente lo ampliaremos para se que parezca un poco más (dentro de lo posible) a las clases que estábamos usando para ocultar SDL.

El primer paso es descargar las herramientas necesarias para crear juegos con XNA: Visual Studio como entorno de desarrollo y XNA Game Studio como biblioteca de juegos.

En primer lugar, descargamos e instalamos Visual Studio. Si queremos ir a la última versión (2010), en su variante “Express” (de evaluación), la podemos encontrar aquí:

http://www.microsoft.com/express/Downloads/#2010-Visual-CS

Podemos optar entre descargar sólo Visual C# en castellano (se descarga un instalador de pequeño tamaño, que luego va descargando progresivamente todo lo que necesita) o bien una imagen ISO que contiene todo Visual Studio, para instalar posteriormente en local.

Después descargamos e instalamos XNA. Su última versión en estos momentos es la 4, sólo en inglés, que podemos encontrar aquí:

http://www.microsoft.com/downloads/en/details.aspx?FamilyID=9ac86eca-206f-4274-97f2-ef6c8b1f478f


Si ahora entramos a Visual Studio e indicamos que queremos crear un Nuevo proyecto. Entre las plantillas que se nos proponen, debería aparecer una llamada “Windows Game (4.0)”.

Damos un nombre al proyecto y aparecerá un fuente llamado “Game1.cs”, que contiene algo similar a (eliminando los comentarios):

public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;

public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}

protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}

protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// TODO: use this.Content to load your game content here
}

protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}

protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
base.Update(gameTime);
}

protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
base.Draw(gameTime);
}
}

Las ideas básicas son:
  • “Initialize” es la función de inicialización. En principio, debería crear la infraestructura que fuera necesaria, a excepción de los gráficos.
  • “LoadContent” se encarga de cargar el “contenido” que fueramos a emplear. Ahí preparemos nuestras imágenes.
  • “UnloadContent” se encargará del paso contrario, si fuera necesario (en nuestros ejemplos simples no lo será).
  • “Update” (actualizar) se debe encargar de toda la lógica de juego: actualizar el mundo, comprobar colisiones, comprobar entrada del usuario -teclas, joystick, ratón-, reproducir sonido, etc.
  • “Draw” dibuja los elementos en pantalla.


Si queremos acercarlo un poco a nuestro estilo, la imagen del personaje sería un “Texture2D” (una textura en dos dimensiones), que declararíamos en la parte de atributos:

Texture2D imagenPersonaje;

Para cargar la imagen, podemos “esquivar” los “contenidos” de XNA y hacerlo a nuestra manera, cargando un fichero PNG desde el programa. Esto, en XNA 3.1 se puede conseguir con Texture2D.FromFile:

imagenPersonaje = Texture2D.FromFile(graphics, "imagenes\\personaje.png");

pero esta sintaxis no es válida en XNA 4, sino que tenemos que usar “FromStream”, un poco más incómodo, porque deberemos leer la imagen desde un “FileStream”, así por ejemplo:

imagenPersonaje = Texture2D.FromStream(graphics.GraphicsDevice,
new FileStream ("imagenes\\personaje.png",FileMode.Open));

(como usamos un FileStream, deberemos añadir “using System.IO;” al principio de nuestro fuente).

La alternativa fácil es dejar las imágenes prefijadas, como parte del “contenido” (content) del proyecto, pero no estamos buscando la solución más fácil, sino una que recuerde a nuestra forma anterior de trabajar, cuando usábamos Tao.SDL..

Para la posición, podemos usar dos números enteros, x e y, o podemos emplear un tipo de datos existente en XNA, el “Vector2” (un vector de 2 componentes): lo declararíamos como atributo:

Vector2 posicion;

al que daremos valor desde LoadContent:

posicion = new Vector2(400, 300);

Desde “Update” podemos comprobar si se pulsa ESC para salir o alguna de las flechas de dirección para cambiar la posición del personaje:

if (Keyboard.GetState().IsKeyDown(Keys.Escape))
this.Exit();

if (Keyboard.GetState().IsKeyDown(Keys.Left))
posicion.X -= 5;
if (Keyboard.GetState().IsKeyDown(Keys.Right))
posicion.X += 5;
if (Keyboard.GetState().IsKeyDown(Keys.Up))
posicion.Y -= 5;
if (Keyboard.GetState().IsKeyDown(Keys.Down))
posicion.Y += 5;

Y para dibujar el personaje, y los demás “sprites” del juego, lo haremos desde “Draw”, como parte del “lote de sprites” (spriteBatch), así:

protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);

spriteBatch.Begin();
spriteBatch.Draw(imagenPersonaje, posicion, Color.White);
spriteBatch.End();

base.Draw(gameTime);
}

Si todos los cambios han ido bien, nuestro proyecto debería compilar correctamente y quizá hasta funcionar, con dos consideraciones:
  • Deberemos crear una carpeta “imagenes” dentro de la carpeta del ejecutable de nuestro proyecto (bin/debug), y copiar en ella la imagen llamada “personaje.png”.
  • Es posible que al lanzar el proyecto, se queje de que nuestra tarjeta gráfica no es lo suficientemente potente y “no soporta un perfil HiDef”. No es problema: vamos al menú Proyecto, escogemos la opción “Propiedades de... (el nombre del proyecto)” y en la primera pestaña, en el apartado “Game profile”, dejamos activada la opción “Use Reach” en vez de “Use HiDef”.


Puedes descargar el mini-proyecto desde su página en Google Code, con el nombre miner001XNA:

http://code.google.com/p/manic-miner/downloads/list