October 2009 - Artículos

Este código de ejemplo que podéis descargar encontrareis una aplicación XNA con diferentes pantallas.

El proyecto es el siguiente:

Evidentemente no voy a explicarlo todo porque saldría un pedazo de post, a grandes rasgos :

Content : las imágenes, siguiendo el mismo patrón que en el post anterior de SpriteBase, más la carpeta Screens que contiene las imágenes que mostraremos en las diversas pantallas.

CFUtil : En esta carpeta tenemos las utilidades que utilizo en las clases principales, igual que en el articulo Spritebase, aquí tenemos el ScreenBase que utilizaremos para generar las diferentes pantallas.

         Dentro encontramos dos clases que heredan de DrawableGameComponent, que son ImatgeComponent que brinda la funcionalidad de poner una imagen de fondo centrada, a toda pantalla o en una posición indicada para una pantalla, y MenuComponent que genera el menú de la pantalla principal (Jugar/Ayuda/Acerca de…/Salir)

Respecto a las clases principales vemos que tenemos todas la del ejemplo de SpriteBase, las cuales son utilizadas cuando le damos a la opción jugar. Debido a que no es un ejemplo de un juego, sino de cómo generar las pantallas, el juego en si será el mismo ejemplo que el articulo anterior.

Las nuevas clases son las terminadas en Screen:

MenuScreen :

La pantalla principal donde hay un menú para seleccionar las opciones principales :

 

A nivel de código se hereda de ScreenBase y en el constructor se añaden dos componentes ImageComponent y un MenuComponent :

  class MenuScreen:ScreenBase

    {

        private ImageComponent imgGeeks;

        private ImageComponent imgAvion;

        public MenuComponent menu;

 

        public MenuScreen(Game game)

            : base(game)

        {

            this.menu = new MenuComponent(game);

 

            this.imgGeeks = new ImageComponent(game, base.Game.Content.Load<Texture2D>("Screens/geeks")

                                   , ImatgeMode.Custom,new Vector2());

            this.imgAvion = new ImageComponent(game, base.Game.Content.Load<Texture2D>("Screens/1945")

                                                , ImatgeMode.Custom, new Vector2(300, 100));

 

            this.imgAvion.pos = new Vector2(300, 100);

            base.Components.Add(this.imgAvion);

            base.Components.Add(this.imgGeeks);

            base.Components.Add(this.menu);

        }

    }

HelpScreen :

La pantalla donde se nos muestra la información de ayuda :

   class HelpScreen : ScreenBase

    {

        private SpriteFont textFont;

        private SpriteBatch spriteBatch;

 

        public HelpScreen(Game game)

            : base(game)

        {

            base.Components.Add(new ImageComponent(game, base.Game.Content.Load<Texture2D>("Screens/help")

                                                ,ImatgeMode.Stretch,new Vector2()));

            this.textFont = Game.Content.Load<SpriteFont>("Font//Verdana");

            this.spriteBatch = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));

        }

 

        public override void Draw(GameTime gameTime)

        {

            base.Draw(gameTime);  //primero ponemos la imagen y después el texto encima.

            spriteBatch.DrawString(this.textFont, "Intrucciones :\n  1 - Avion\n  2 - Explosion\n  3 - Asteroide\n  4 - Personaje\n  Escape - Salir ",

                                    new Vector2(95, 135),

                                    Color.Blue);

        }

    }

Bien en esta pantalla a parte de poner un ImageComponet como fondo de pantalla, también tenemos un ejemplo de cómo dibujar en ella un texto por ejemplo.

AboutScreen :

Pantalla donde muestra el típico Acerca de nuestra aplicación.

    class AboutScreen : ScreenBase

    {

        private SpriteFont textFont;

        private SpriteBatch spriteBatch;

 

        public AboutScreen(Game1 game)

            : base(game)

        {

            base.Components.Add(new ImageComponent(game, base.Game.Content.Load<Texture2D>("Screens/geeks")

                                               , ImatgeMode.Custom,new Vector2()));

            this.textFont = Game.Content.Load<SpriteFont>("Font//About");

            this.spriteBatch = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));

        }

        public override void Draw(GameTime gameTime)

        {

            Game.GraphicsDevice.Clear(Color.White);

            spriteBatch.DrawString(this.textFont,

                                    "Acerca de... Screen Sample ",

                                    new Vector2(105, 45),

                                    Color.Black);

            spriteBatch.DrawString(this.textFont,"Esta aplicacion es un ejemplo de como generar diferentes pantallas\nde menu para nuestros juegos. \n\n Autor:Carlos Fouz\n www.geeks.ms/blogs/cfouz",  new Vector2(105, 155), Color.Black);

             base.Draw(gameTime);

        }

    }

  PlayScreen :

En esta pantalla se ejecutaría el juego en si, en este ejemplo lo que he puesto es lo mismo que en el ejemplo anterior de SpriteBase.

Bien ahora ya creo que tenemos los conocimientos básicos para poder empezar a crear un juego simple, utilizando este ejemplo como esqueleto.

Os animo a que os descarguéis el código : CFScreens.zip

con no comments
Archivado en:

Objectivo:

 

- Generar una clase abstracta que nos brinde toda la funcionalidad necesaria para realizar nuestros frames2D de una manera muy simple.

 

- Generar un ejemplo de cada tipo de frame que podemos tener en nuestro juego, como inanimado, animado, animación continua (loop) o un personaje que ande en todas direcciones.

 

Requerimientos :

 

- Heredar la clase abstracta, para establecer el tipo de frame que es (animado, inanimado, con o sin loop) y gestionar la posición en pantalla.

 

- Cargar las textura/as del frame.

 

- Publicar com servicio el objeto SpriteBatch en la clase Game :

 

Services.AddService(typeof(SpriteBatch), spriteBatch);

 

 

Diseño de la clase SpriteBase.cs

 

Atributos :

 

protected Vector2 position;         //posicion del frame en pantalla

protected bool isAnimate=false;     //indica si tiene animación

protected bool loop = false;     //indica si la animacion tiene loop

protected int activeFrame;          //indicador del frame actual

protected int initFrame;  //indicador del primer frame de la animación

protected int lastFrame;  //indicador del ultimo frame de la animación

protected Texture2D[] textura;      //textura

protected long frameDelay;          //refresco

 

private TimeSpan elapsedTime = TimeSpan.Zero;

private SpriteBatch sBatch;       //almacenado en Services

 

Métodos :

 

public SpriteBase(Game game): base(game)

En el qual recogeremos el SpriteBatch.

 

public override void Update(GameTime gameTime)

Donde gestionaremos las animaciones .

 

public override void Draw(GameTime gameTime)

Donde pintaremos nuestro frame.

 

Diseño de la solución :

 

 

 

 

A grandes rasgos lo que se pretende es que construyamos nuestra clase heredando de SpriteBase y nos olvidemos de las cosas comunes en la gestión de frames en juegos 2D.

 

Implementación :

 

Para la gestión de nuestros sprites lo único que tenemos que hacer es heredar de SpriteBase y gestionar los atributos de la misma, así como cargar las textura/as y modificar la posición si tiene movimiento.

 

- Dibujar un sprite simple (un avión)

 

public class Avion: SpriteBase

{

public Avion(Game game, FrameRate frameRate): base(game)

        {

            base.frameDelay = long.Parse(frameRate.GetHashCode().ToString());

            base.isAnimate = false; //no es una animación

            base.position = new Vector2(game.Window.ClientBounds.Width / 2, game.Window.ClientBounds.Height / 2);

            base.textura = new Texture2D[1];

            base.textura[0] = base.Game.Content.Load<Texture2D>("avion/avion");

        }

}

Con esto tenemos suficiente, podemos implementar el método update para modificar su posición en pantalla controlando el teclado si lo creemos necesario. Por ejemplo :

 

       public override void Update(GameTime gameTime)

        {

            KeyboardState keyboard = Keyboard.GetState();

            if (keyboard.IsKeyDown(Keys.Up))

               base.position.Y -= 3;

           

            if (keyboard.IsKeyDown(Keys.Down))

              base.position.Y += 3;

           

            if (keyboard.IsKeyDown(Keys.Left))

                base.position.X -= 3;

           

            if (keyboard.IsKeyDown(Keys.Right))

                base.position.X += 3;

           

            base.Update(gameTime);

        }

El resultado por pantalla es:

 - Generar un bucle de animación (un asteroide rotando)

 class Asteroide:SpriteBase

{

  public Asteroide(Game game, FrameRate frameRate): base(game)

  {

   base.frameDelay = long.Parse(frameRate.GetHashCode().ToString());

   base.isAnimate = true;  //indicamos que es una animación

   base.loop = true;       //indicamos que es un bucle

   this.lastFrame = 7;     //indicamos ultimo frame de la animación

   base.position = new Vector2(game.Window.ClientBounds.Width / 2, game.Window.ClientBounds.Height / 2);

   this.CargaTextura();

   }

private void CargaTextura()

  {

   base.textura = new Texture2D[8];

   base.textura[0] =      base.Game.Content.Load<Texture2D>("asteroide/asteroide1");

   base.textura[1] = base.Game.Content.Load<Texture2D>("asteroide/asteroide2");

   base.textura[2] = base.Game.Content.Load<Texture2D>("asteroide/asteroide3");

   base.textura[3] = base.Game.Content.Load<Texture2D>("asteroide/asteroide4");

   base.textura[4] = base.Game.Content.Load<Texture2D>("asteroide/asteroide5");

   base.textura[5] = base.Game.Content.Load<Texture2D>("asteroide/asteroide6");

   base.textura[6] = base.Game.Content.Load<Texture2D>("asteroide/asteroide7");

   base.textura[7] = base.Game.Content.Load<Texture2D>("asteroide/asteroide8");

   }

 }

 El resultado por pantalla es:

 -  Generar una animación sin bucle (una explosión)

 public class Explosion:SpriteBase

{

  public Explosion(Game game, FrameRate frameRate): base(game)

   {

   base.frameDelay = long.Parse(frameRate.GetHashCode().ToString());

   base.isAnimate = true; //indicamos que es una animación

   base.lastFrame = 6;    //indicamos ultimo frame de la animación

   base.loop = false;     //indicamos que no es un bucle

   base.position = new Vector2(game.Window.ClientBounds.Width / 2,game.Window.ClientBounds.Height / 2);

   this.CargaTextura();

   }     

 private void CargaTextura()

   {

    base.textura = new Texture2D[7];

    base.textura[0] = base.Game.Content.Load<Texture2D>("explosion/explo1");

    base.textura[1] = base.Game.Content.Load<Texture2D>("explosion/explo2");

    base.textura[2] = base.Game.Content.Load<Texture2D>("explosion/explo3");

    base.textura[3] = base.Game.Content.Load<Texture2D>("explosion/explo4");

    base.textura[4] = base.Game.Content.Load<Texture2D>("explosion/explo5");

    base.textura[5] = base.Game.Content.Load<Texture2D>("explosion/explo6");

    base.textura[6] = base.Game.Content.Load<Texture2D>("explosion/explo7");

    }

}

 El resultado por pantalla es:

 

 -  Generar un personaje

 Esta clase la podeis descargar para ver como funciona, es exactamente que una animación con loop pero en el método update asignamos a las variables initFrame, activeFrame i lastFrame el valor de cada animación en función de la dirección del personaje.

 

El resultado por pantalla es:

 Bien os insto a que os descarguéis el código fuente para testearlo, lo encontrareis todo comentado para que sea más fácil de entender.

 CFSpriteBase.zip

 

con 1 comment(s)
Archivado en: