domingo, 6 de junio de 2010

Programando videojuegos: Tutorial XNA Game Studio 4.0 parte 1

crab-icon ball c#

Antes de nada quiero disculparme por la ausencia de las ultimas semanas, he estado demasiado ocupado como para poner ninguna entrada, pero ya estoy de vuelta, y empiezo fuerte.

En las próximas entradas, vamos a trabajar sobre XNA, un entorno de desarrollo proporcionado por Microsoft para el desarrollo de juegos 2D y 3D. Tiene un montón de ventajas, pero en mi opinión la mas importante es la portabilidad del código a la hora de trasladar un juego entre las diferentes plataformas soportadas (PC, XBox 360 y Windows Phone). Evidentemente no es lo mismo trabajar con la pantalla de un móvil que con una tele, pero las diferencias en cuanto a código se reducen a eso y a los controles del juego.

Quiero mencionar que este tutorial esta orientado tanto a gente que nunca ha programado videojuegos como a gente que nunca ha utilizado XNA. Solo se requieren conocimientos básicos de C#, e intentare ir paso por paso y explicarlo todo con detalle.

Para este tutorial, dividido en varias partes, vamos a desarrollar un juego para Windows (Un juego de naves en 2D), pero no es nada difícil trasladar este código a cualquiera las plataformas anteriormente mencionadas. ¿Que necesitamos para empezar a programar en XNA game studio? Pues simplemente, un visual studio y una versión de XNA Game Studio compatible con este. Yo voy a utilizar VS 2010 y XNA GS 4.0 por ser las ultimas versiones de ambos, pero las diferencias en cuanto al código deberían ser mínimas.

¿Donde conseguimos XNA Game Studio? Muy fácil, aquí mismo: http://creators.xna.com/es-ES/downloads

Una vez tenemos todo instalado podemos comenzar a programar. Lo primero que haremos será crear un nuevo proyecto de XNA para Windows Games.

imageTras esto veremos que nos autogenera ya bastantes cosas. La clase principal es la que nos habrá llamado Game1 y tiene los siguientes métodos:

  • Initialize se llama al principio de la ejecución del juego. En principio lo utilizaremos para crear instancias de los objetos que vamos a necesitar y para cambiar cosas como el titulo de la ventana.
  • LoadContet se llama después de Initialize. Este método creara una instancia de SpriteBatch, la cual usaremos para dibujar cosas por pantalla mas adelante. Además es aquí donde debemos cargar las imágenes de nuestro juego.
  • Update se llamara varias veces por segundo a lo largo de la ejecución del juego, y aquí deberemos insertar la lógica del juego.
  • Draw se llamara varias veces por segundo también y se encargara de dibujar cosas por pantalla valiéndose del antes mencionado SpriteBatch. Es importante tener en cuenta de que si una cosa se dibuja mas tarde que otra, la que mas tarde se dibuje quedara por encima de la otra.

Si probamos a ejecutar veremos una pantalla en azul.

image

No es gran cosa, pero es el comienzo de nuestro juego. Lo primero que debemos notar es que ese fondo azul no nos sirve (si alguien quiere hacer un juego de una piscina quizás sirva, pero nosotros vamos a hacer un juego de naves) así que cambiaremos el color de fondo por negro. Para ello habrá que modificar el método Draw:

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

// TODO: Add your drawing code here

base.Draw(gameTime);
}


Con esto el fondo de nuestra aplicación ya será negro. En partes posteriores de este tutorial se explicara como cambiar el fondo e incluso animarlo. El próximo paso para que la ventana sea mas adecuada a nuestras necesidades es cambiar el titulo. Esto lo insertamos dentro del método Initialize:



protected override void Initialize()
{
// TODO: Add your initialization logic here
this.Window.Title="Space Burst";
base.Initialize();
}




Tras esto la ventana ya esta preparada para nuestro juego, con un fondo negro y Space Burst de titulo,battleship el próximo exitazo de ventas esta preparado para arrancar :P. Ahora toca preguntarnos que es lo que falta en nuestro juego? Es un juego de naves, así que es bueno tener alguna. Yo voy a utilizar la siguiente imagen, que es un sprite con varias posiciones de una nave



Para añadir la imagen a nuestro proyecto la copiamos en la carpeta del proyecto y la añadimos (arrastrándola mismamente) a Content de nuestro proyecto. Esto será una especie de proyecto a parte para los que usen XNA GS 4.0 o una carpeta en caso de usar versiones anteriores.



Ahora crearemos la clase Nave. Podríamos poner todo dentro de la clase Game1, pero el código resultante no sería nada elegante. Añadimos la nueva clase al proyecto Click derecho>Añadir>Clase y comenzamos con nuestra nave. Antes de nada y para evitar futuros problemillas añadiremos los diferentes imports necesarios:



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


¿Que atributos necesitamos que tenga? Pues vamos a ir poco a poco, así que empezaremos con 2: un objeto Texture2D donde se almacenara la imagen y un objeto Vector2 donde se almacenara la posición.




private Texture2D imagen;
private Vector2 posicion;


Además de esto, tendremos que añadir a la clase nave los métodos importantes de la clase Game1: LoadContent, Update y Draw, y así en la clase Game1 solo tendremos que llamar en cada método a los métodos correspondientes de todos los objetos que tengamos en la pantalla.



Debemos crear la instancia de posición dentro del constructor de la clase y la de imagen dentro de LoadContent. Como algo opcional podremos pasar al constructor de nave el ancho y alto de la ventana, para saber donde dibujar inicialmente la nave y que no quede demasiado descentrada:



 public Nave(int altoVentana, int anchoVentana)
{
posicion = new Vector2(altoVentana-100, (anchoVentana)/2);
}
public void LoadContent(ContentManager Content)
{
imagen = Content.Load<Texture2D>;("battleship");
}
public void Update()
{

}


El parámetro ContentManager es necesario para cargar imágenes, y lo pasamos al invocar el método desde la clase principal. Hay que notar que el nombre de la imagen se escribe sin terminación. Esto es importante, por que sino no te encontrara tu imagen. También añadimos ya el método Update de la clase nave, aunque aún no haga nada.




Aprovecho para explicar el sistema de coordenadas utilizado por XNA. Las medidas son en pixeles y al contrario que el sistema cartesiano el eje (0,0) esta situado en la parte superior izquierda de la ventana. Así por ejemplo si tenemos una ventana de 800x600 el punto (800, 600) sería la esquina inferior derecha, (800, 0) sería la esquina superior derecha y (0, 600) la esquina inferior izquierda.



Tras esto implementamos el método Draw de Nave, que dibujara la imagen en la posición adecuada:



public void Draw(SpriteBatch spbtch)
{
spbtch.Draw(imagen, posicion, new Rectangle(42, 88, 42, 44), Color.White);
}


Que es todo esto, os preguntareis. Lo primero es el parámetro, el objeto SpriteBatch anteriormente comentado, que se encarga de dibujar cosas por pantalla. Lo utilizamos para llamar al metodo Draw. Pide varios parámetros: con imagen le pasamos la imagen que debe dibujar, con posición le pasamos donde debe dibujarla (hasta ahí espero que lo entendáis bien), pero ¿que es ese Rectangle? Pues muy sencillo. Nuestra imagen tiene varias imágenes de la nave en diferentes posiciones, y ese Rectangle indica que parte de la imagen hay que dibujar. En caso de que la imagen fuese una sola no haría falta este parámetro. Los números que necesita para crearse son las coordenadas donde empieza a dibujar, x e y por ese orden, y el ancho y alto de la imagen. Nuestra imagen consta de 9 imágenes de 42x44, así que con esos parámetros debería dibujar la imagen central.



Tras esto solo queda crear una instancia de Nave y llamar a los métodos necesarios en la clase Game1:



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

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

protected override void Initialize()
{
// TODO: Add your initialization logic here

_nave = new Nave(graphics.PreferredBackBufferHeight, graphics.PreferredBackBufferWidth);
this.Window.Title="Space Burst";
base.Initialize();
}

protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
_nave.LoadContent(Content);
}

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

protected override void Update(GameTime gameTime)
{
// Cuidado con esto, no usamos mando.
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
this.Exit();
_nave.Update();

base.Update(gameTime);
}

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

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

base.Draw(gameTime);
}
}


Como veréis, en el método LoadContent pasamos a Nave la anchura y la altura de nuestra ventana. En Update hay que tener cuidado, puesto que al menos a mi, en el código autogenerado comprobaba que estuviese pulsado el botón Atrás dentro de un gamepad (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed), y como probablemente nosotros usaremos teclado, tenemos que cambiar eso por la tecla escape, como se puede ver en el código. Además de esto llamamos al método Update de nave que aunque no haga nada, pronto lo hará. También llamamos a _nave.Draw dentro del metodo Draw principal, pasando como parametro el SpriteBatch.



Tras todo esto, si probamos a ejecutar, veremos algo similar a esto:




image

Aún no se mueve, ni hace nada, pero que esperabais, Roma no se construyo en un día. ¿Ha sido largo? No mucho. ¿Ha sido difícil? para nada.




image

Con esto concluyo esta titánica entrada que se me ha alargado bastante mas de lo que esperaba. Muy pronto sacare la segunda parte, para que nuestra navecita ya pueda hacer cosas. ¡Sed unos cangrejos pacientes!





Etiquetas de Technorati: ,,,,,

28 comentarios:

  1. Hola:

    Este tutorial está buenísimo. Explciando detalle por detalle, así conseguirás que muchas personas, sobre todo indecisas a meterse al mundo del XNA Game Studio con C#.

    Muchos ánimos con el tutorial siguiente, está de lujo.

    Un cordial saludo.

    ResponderEliminar
  2. Me alegro que te haya gustado tanto, seguire con el tutorial siempre que tenga tiempo para ello. Ahora el problema sera difundirlo, este blog es nuevo y aun no me sigue mucha gente :P

    ResponderEliminar
  3. Buenas:

    El truco que conozco es ir registrándote en muchos foros (90 foros) que tenga algo de programación y poner un tema que presentas el tutorial. Ya verás el cambio.

    Saludo.

    ResponderEliminar
  4. Muy bueno el tutorial, estoy haciendolo a ver que tal.

    ResponderEliminar
  5. me encanta tu blog,lo seguiré de cerca,aunque solo se programar en C xD.Saludos

    ResponderEliminar
  6. Hola, voy siguiendo tu tutorial, solo decir que está muy bien, y comentar algun errorcillo que va saliendo: Creo que le pasas al revés la posición inicial de la nave, debería ser Vector2(x, y):

    public Nave(int altoVentana, int anchoVentana)
    {
    posicion = new Vector2((anchoVentana) / 2, altoVentana - 100);
    }

    Una chorradilla pero a los que estamos empezando nos puede crear algo de confusión.

    Un saludo

    ResponderEliminar
  7. Amiga muchas gracias, el tutorial esta buenisimo.

    ResponderEliminar
  8. en esta parte tenes un pequeño error
    imagen = Content.Load;("battleship");
    es:
    imagen = Content.Load("battleship");

    ResponderEliminar
  9. Hola!
    Felicitarte por el enorme trabajo que estás realizando con el blog, quiero iniciarme en la programación con XNA y tus tutoriales me son de mucha utilidad :D

    Un saludo.

    ResponderEliminar
  10. hola me gustaría aprender mas sobre esto mira tengo conocimientos en java estuve viendo como programar en c# pero es muy parecido al java, me gustaría que me recomiendes si debo aprender primero c# para aplicaciones pc y después pasar al xna, y si tienes algunas paginas del lenguaje xna.

    ResponderEliminar
  11. Genial sigue asi... yo soy programador C# pero no he trabajado con xna... gracias ahora podre iniciarme con algo...

    ResponderEliminar
  12. Esta muy bueno, te felicito.. pero tengo un problema.. no entiendo la parte del "Content.Load".. mi archivo se llama "battleship.png" y en el codigo pongo como parametro solo "battleship" y me dice que no encuentra.. me puedes ayudar? gracias!

    ResponderEliminar
  13. holA

    es un muy buen trabajo el que haces, soy un estudiante, pertenezco a un grupo enfocado a tecnologías.NET y me gustaría saber si tu podrías colaborar con nuestro programa.
    Hay te dejo el link de nuestra pagina de facebook.

    http://www.facebook.com/pages/Student-Tech-Antonio-Jose-Camacho/144983988876658

    ResponderEliminar
  14. que tal, la verdad que me gusto mucho el tutorial, pero me quedo una duda, donde tengo q escribir todo el codigo ? porque no me queda muy claro... Ya se que lo de Private Vector2D Posicion va en la clase nave.cs, pero el resto ? xq cuando lo escribo todo ahi en la clase me sigue tirando la pantalla celeste. Espero que puedas ayudarme, un saludo grande desde TuReceta.wordpress.com

    ResponderEliminar
  15. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  16. Esta buenisimo lo estado haciendo pero lo he traducido todo en basic no se si podrias hacerlo en en otros lenguajes como F# o basic o talves para XBOX :).....Me encato

    ResponderEliminar
  17. hola quisiera saber cual e el precio de la plataforma de xna game studio xfavor

    ResponderEliminar
  18. hola soy nueva en esto de xna y mientras buscaba tutoriales me encontre con tu pagina
    esta muy bien explicado para que es cada cosa pero hay una linea que me marca error
    y aunque me queda claro para que sirve no se como acomodarla

    imagen = Content.Load;("battleship");

    podrias o podria explicarme alguien porque me marca error???

    ResponderEliminar
    Respuestas
    1. esta respondido mas arriba, sobra el ; entre la palabra Load y ("battleship")

      Eliminar
  19. Hola oye si me gusta mucho el tutorial, mi sueño siempre ha sido crear videojuegos, y que mejor que aprenderlo con programacion, sigue con los tutoriales porfavor estan buenisimos sigue sigue no pares porfavor, nunca dejes que desaparesca este blog porfa, muchisimas gracias, estoy siguiendo el tutorial y si habia un error, ospinaospinacristian ya me lo resolvio, Celina el error es que en: imagen = content.load;("battleship") seria asi: imagen = content.load("battleship") es decir el error esta en el punto y coma. pero vas increible cangreja sigue asi chao.

    ResponderEliminar
  20. Hola que ondas... pues el tutorial esta muy bueno, pero a mi me marca un error en la línea de: Imagen = Contenido.Load("battleship"); Me dice que el archivo no fue encontrado, alguien sabe a que se debe esto...

    ResponderEliminar
  21. Muchas gracias y continúa con tu blog! Me ha servido muchísimo para un proyecto de la universidad :)

    ResponderEliminar
  22. private Texture2D imagen;
    private Vector2 posicion; oyes estas dos me marcan error que esta mal

    ResponderEliminar
  23. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  24. Bueno, aqui estoy otra vez...estoy disfrutando mucho con tu tutorial, es estupendo. Pero ahora si que me he quedado bloqueado, no tengo claro del todo donde hay que poner la imagen de la nave, yo he puesto un fichero "battleship" en el directorio Content del proyecto pero me sale un error que no puede cargar el fichero...

    ResponderEliminar
  25. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  26. alguien tide el codigo completo del programa porfa?

    ResponderEliminar