“Scrolling background” – moviendo multiples fondos


En los juegos 2D es muy importante hacer sentir al usuario la sensación de que el juego es casi real, para eso muchas veces se usan técnicas con diferentes fondos, y cada fondo se mueve a una velocidad distinta, dando una sensación 3D, por ejemplo en Mario Bross, había un fondo el del césped y el de los tubitos que se movia a la velocidad de Mario, más al fondo habían un fondo de montaña que se movía más lento, y en otras oportunidades había otro fondo mucho más profundo que casi ni se movía.

 En términos más técnicos estamos hablando del Scroll Parallax, entre más fondos o capas tengamos, el efecto va a ser mucho mejor.

Me he puesto en la tarea de crear unos bellos dibujos para nuestro ejemplo:

Los he creado en Paint.net para poder dejarles partes transparentes, ahora creamos un nuevo proyecto en XNA, y adicionamos una clase nueva al proyecto.

Nombramos la clase como Fondo.cs, luego creamos la siguiente clase:

class Fondos
{
      public Texture2D dibujo;
      public Vector2 posicion = Vector2.Zero;
      public float profundidad = 0.0f;
      public float velocidad = 0.0f;
      public int direccion = -1;
      public Vector2 tamañodibujo = Vector2.Zero;
      public Color color = Color.White;
}

Esta clase, nos muestra la definición de una capa o un fondo, tenemos atributos tales como la posición, profundidad, velocidad, dirección, entre otros.

Ahora creamos en el mismo archivo otra clase que maneje muchos fondos, y los mueva de acuerdo a la velocidad, además de ordenarlos por su profundidad, la definición y explicación de la clase:

class MultiFondos
{
      private bool moviendose = false;
      private bool moverHorizontal = true;
      private Vector2 Ventana;
      private List<Fondos> listafondos = new List<Fondos>();
      private SpriteBatch batch;
      public MultiFondos(GraphicsDeviceManager graficos)
      {
            Ventana.X = graficos.PreferredBackBufferWidth;
            Ventana.Y = graficos.PreferredBackBufferHeight;
            batch = new SpriteBatch(graficos.GraphicsDevice);
      }
      public void AdicionarFondo(Texture2D dibujo, float profundidad, float velocidad, int direccion)
      {
            Fondos fondo = new Fondos();
            fondo.dibujo = dibujo;
            fondo.profundidad = profundidad;
            fondo.velocidad = velocidad;
            fondo.tamañodibujo.X = dibujo.Width;
            fondo.tamañodibujo.Y = dibujo.Height;
            fondo.direccion = direccion;
            listafondos.Add(fondo);
      }
      public int CompararProfundidades(Fondos fondo1, Fondos fondo2)
      {
            if (fondo1.profundidad < fondo2.profundidad)
            {
                  return 1;
            }
            if (fondo1.profundidad > fondo2.profundidad)
            {
                  return -1;
            }
            if (fondo1.profundidad == fondo2.profundidad)
            {
                  return 0;
            }
            return 0;
      }
      public void Mover(float velocidad)
      {
            float velocidadMovimiento = velocidad / 60.0f;
            foreach (Fondos fondo in listafondos)
            {
                  float distanciaMovimiento = fondo.velocidad * velocidadMovimiento;
                  if (!moviendose)
                  {
                        if (moverHorizontal)
                        {
                              fondo.posicion.X += (distanciaMovimiento * fondo.direccion);
                              fondo.posicion.X = fondo.posicion.X % fondo.tamañodibujo.X;
                        }
                        else
                        {
                              fondo.posicion.Y += (distanciaMovimiento * fondo.direccion);
                              fondo.posicion.Y = fondo.posicion.Y % fondo.tamañodibujo.Y;
                        }
                  }
            }
      }
      public void Dibujar()
      {
            listafondos.Sort(CompararProfundidades);
            batch.Begin();
            for (int i = 0; i < listafondos.Count; i++)
            {
                  if (!moverHorizontal)
                  {
                        if (listafondos[i].posicion.Y < Ventana.Y)
                        {
                              batch.Draw(listafondos[i].dibujo, new Vector2(0, listafondos[i].posicion.Y - listafondos[i].tamañodibujo.Y), listafondos[i].color);
                        }
                        else
                        {
                              batch.Draw(listafondos[i].dibujo, new Vector2(0, listafondos[i].posicion.Y + listafondos[i].tamañodibujo.Y), listafondos[i].color);
                        }
                  }
                  else
                  {
                        if (listafondos[i].posicion.X < Ventana.X)
                        {
                              batch.Draw(listafondos[i].dibujo, new Vector2(listafondos[i].posicion.X, 0), listafondos[i].color);
                        }
                        if (listafondos[i].posicion.X > 0.0f)
                        {
                              batch.Draw(listafondos[i].dibujo, new Vector2(listafondos[i].posicion.X - listafondos[i].tamañodibujo.X, 0), listafondos[i].color);
                        }
                        else
                        {
                              batch.Draw(listafondos[i].dibujo, new Vector2(listafondos[i].posicion.X + listafondos[i].tamañodibujo.X, 0), listafondos[i].color);
                        }
                  }
            }
            batch.End();
      }
      public void MoverVertical()
      {
            moverHorizontal = false;
      }
      public void MoverHorizontal()
      {
            moverHorizontal = true;
      }
      public void Parar()
      {
            moviendose = false;
      }
      public void IniciarMover()
      {
            moviendose = true;
      }
      public void SetPosicionFondo(int numeroFondo, Vector2 posicionIncial)
      {
            if (numeroFondo < 0 || numeroFondo >= listafondos.Count) return;
            listafondos[numeroFondo].posicion = posicionIncial;
      }
      public void SetTransparencia(int numberFondo, float porcentaje)
      {
            if (numberFondo < 0 || numberFondo >= listafondos.Count) return;
            float alpha= (porcentaje/ 100.0f);
            listafondos[numberFondo].color = new Color(new Vector4(0.0f, 0.0f, 0.0f, alpha));
      }
      public void Actualizar(GameTime gameTime)
      {
            foreach (Fondos fondo in listafondos)
            {
                  float distanciaMovimiento = fondo.velocidad / 60.0f;
                  if (moviendose)
                  {
                        if (moverHorizontal)
                        {
                              fondo.posicion.X += (distanciaMovimiento * fondo.direccion);
                              fondo.posicion.X = fondo.posicion.X % fondo.tamañodibujo.X;
                        }
                        else
                        {
                              fondo.posicion.Y += (distanciaMovimiento * fondo.direccion);
                              fondo.posicion.Y = fondo.posicion.Y % fondo.tamañodibujo.Y;
                        }
                  }
            }
      }
}

La clase MultiFondos, va a ser la encargada de posicionar y mover los fondos, en el constructor estamos recibiendo un objeto de tipo GraphicsDeviceManager, para luego poder dibujar los fondos.

Tenemos dos variables de tipo Boolean: Moviendose y moverHorizontal, que nos sirven para saber si la capa se está moviendo, también tenemos una lista genérica, para ir guardando los fondos.

El primer método que hay es el de AdicionarFondo, este método recibe los parámetros básicos para inicializar la clase Fondo, luego se adiciona el fondo a la lista.

El segundo método, CompararProfundidades que nos sirve para ordenar los fondos desde el más profundo al más visible, este método recibe dos fondos y compara su propiedad profundidad.

El método Mover(velocidad), es uno de los más importantes, debido a que este método toma cada fondo de la lista, y verifica si tienen la propiedad moviéndose en true, si sí verificamos la propiedad moverHorizontal, si es verdadero movemos el fondo en el eje de las X, dependiendo de la velocidad que hayamos inicializado y en la dirección especifica, si es -1 lo movemos de derecha a izquierda o de abajo hacia arriba, Si se encuentra en false moveHorizontal se va a mover Verticalmente.

El método Dibujar(), ordena los fondos, y luego hacemos uso de la clase SpriteBatch para dibujar los fondos, de acuerdo a si se va a dibujar Horizontalmente o Verticalmente, y además verifica los limites, para cuando el fondo se haya pasado del límite (salido de la pantalla) entonces volver a empezar a dibujar, esto da una sensación de que el fondo no se acaba.

Los otros métodos nos son útiles para configurar el movimiento de los fondos, y detener la animación.

El método Actualizar hace lo mismo que el método Mover, pero recibe como parámetro la velocidad del juego (GameTime), esta variable cambia dependiendo de la potencia del computador.

Bien, ahora para empezar a ver todo en acción, adicionamos las imágenes al proyecto y creamos las instancias de las nuevas clases, esto lo hacemos en la clase Game1.cs:

MultiFondos fondo;
Texture2D cielo;
Texture2D arboles;
Texture2D paisaje;

En el método Initialize:

fondo = new MultiFondos(graphics);

En el LoadContent:

cielo = Content.Load<Texture2D>("fondocielo");
arboles = Content.Load<Texture2D>("fondoarboles");
paisaje = Content.Load<Texture2D>("fondopaisaje");
fondo.AdicionarFondo(arboles, 0.3f, 150.0f, -1);
fondo.AdicionarFondo(paisaje, 0.5f, 80.0f, -1);
fondo.AdicionarFondo(cielo, 0.9f, 10.0f, -1);

Estamos enviando dirección -1 para que se mueva de derecha a izquierda.

En el método Update():

fondo.Mover(0.5f);

y en el Draw:

fondo.Dibujar();

Listo, terminamos!!!, ahora para ver todo en acción (Definitivamente no sirvo como dibujante o diseñador :()

El código Fuente: Aquí.

Anuncios

Deseas comentar o sugerir algo?

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s