Anterior | Índice
Capítulo 10: Velocidad de Animación
Lenguaje: C#
Para: VS2005 / VS2008
Por Dark-N: hernaldog@gmail.com
Visita mi Blog


http://darknromhacking.com


Objetivo: Animaremos un sprite de 5 formas distintas con tal de mostrar ejemplos prácticos de como manejar la velocidad de la animación.

Cuando se trabajan con sprites, por defecto cuando no se realiza un manejo de velocidades de animación, en cada "tick" que se ejecuta del código, se dibujan los frames a una velocidad de 60 frames por segundo, esto quiere decir, 1 frame cada 0,0166666 segundos, o lo que es lo mismo, 1 frame cada 16 milisegundos aproximadamente.

Si manejamos la velocidad de animación, podemos hacer que cierta animación ande más rápido de lo normal o más lento, de esta forma un puede simular un sin fin de situaciones. Un ejemplo clásico es el de 2 personajes, uno que corre de un lado a otro y otro que solo camina. Ahora, para simular correctamente las acciones de caminar y correr, para el personaje que camina, la velocidad de animación debe ser menor a la del personaje que corre, para esto lo que hacemos es leer cada frame y no pintando inmediatamente, sino que esperando cierto tiempo antes de pintar el siguiente frame.

Por ejemplo, si en nuestro juego, para la animación de caminar/correr, se tiene un sprite con 3 frames como el sprite de abajo:


Si vamos a mostrar un personaje caminando, lo normal es leer al sprite, y mostrar en pantalla de a un frame a la vez, y dejando X tiempo de espera, antes de empezar con el otro frame.
En cambio si lo mostramos al personaje corriendo, debemos hacer lo mismo anterior pero debemos esperar menos tiempo (X - algo) antes de seguir con el siguiente frame.

Ahora vamos a la implementación, como vimos en el capítulo anterior, para el manejo de animaciones, SDL.Net nos provee de la clase AnimationCollection. Esta clase tiene el método Add con varias sobrecargas, y una de ellas es:

AnimationCollection.Add (SurfaceCollection miColeccionSurfaces, Double tiempoEsperaMiliseg)

Donde los parámetros son:

-SurfaceCollection: es la colección de Surfaces cargada previamente, por ejemplo:

SurfaceCollection() miColecionSurfaces = new SurfaceCollection();
miColecionSurfaces.Add(new Surface("sprite_derecha.png"), new Size(24, 32), 0);

-Double: tiempo de espera en milisegundos. SDL.Net por defecto lo setea en 30 milisegundos si no se indica este campo. En nuestro caso es fundamental ya que es el que cambiaremos para más de 30 (en caso que queramos que el tiempo de espera sea mayor) o menor a 30 en caso que queramos que sea menor.

Basados en este método, generaremos 5 animaciones de ejemplo:

   1. Leeremos los 3 frames del sprite y mostraremos la animación sin desplazarse por la pantalla, con el Delay por defecto 30 milisegundos. Por lo tanto usaremos algo así:
  miAnimacioncoeccion.Add(miSurfaceColeccion, 30);

   2. Leeremos los 3 frames del sprite y mostraremos la animación sin desplazarse por la pantalla, con el Delay de 90 milisegundos. Esto lo hará verse más lento que el caso anterior, dando el efecto de que el personaje camina. Por lo tanto usaremos algo así
  miAnimacioncoeccion.Add(miSurfaceColeccion, 90);

   3. Leeremos los 3 frames del sprite y mostraremos la animación desplazándose por la pantalla de a 1 pixels por cada Tick. Este desplazamiento no lo estamos controlando, por lo tanto, lo primero que hacemos es utilizar el método Fps de la clase de SDL.Net Events que a la vez es del Namespace SdlDotNet.Core, que nos permite setear la cantidad frames o ticks por segundos que correrá la aplicación:
   public void Run()
   {
       Events.Fps = 60;
   }

con esto seteamos que cada tick se ejecutará a 60 Ticks por segundo o 60 FPS por lo tanto en cada tick se moverá 1 pixels a la derecha. Por otra parte, usaremos un Delay de animación de 30 milisegundos, por lo que usaremos algo así:
  miAnimacioncoeccion.Add(miSurfaceColeccion, 30);
y en game loop tenemos la lógica:
  ++miAnimatesprite.X;

   4. Leeremos los 3 frames del sprite y mostraremos la animación desplazándose por la pantalla de a 1 pixels por cada Tick. Este desplazamiento si lo estamos controlando, por lo tanto a cada tick que suceda (60 Ticks por segundo), NO se moverá 1 pixels a la derecha inmediatamente como en el caso anterior, sinó que definiremos una variable que tendrá el tiempo que quiero que espere antes de moverse a la derecha, en este caso 48 milisegundos:
  int milisegndosPorFrame = 48.
Además usaremos un Delay de animación de 90 milisegundos por lo que será que se mueve a la derecha pero caminando y no corriendo. Por lo tanto usaremos algo así
  miAnimacioncoeccion.Add(miSurfaceColeccion, 90);
y en Loop
   if (Timer.TicksElapsed - ultimoCalculoFrame >= milisegndosPorFrame)
     {
       ++personaje4.X;
       ultimoCalculoFrame = Timer.TicksElapsed;     
     }


   5. Leeremos los 3 frames del sprite y mostraremos la animación desplazándose por la pantalla de a 2 pixels por cada Tick (más rápido que en el caso 3). Este desplazamiento no lo estamos controlando, por lo tanto a cada tick que suceda (60 Ticks por segundo igual que en el caso 3), se moverá 2 pixels a la derecha. Además usaremos un Delay de animación de 10 milisegundos, por lo que verán que las piernas las mueve realmente rápido. Por lo tanto usaremos algo así
  miAnimacioncoeccion.Add(miSurfaceColeccion, 10);
y en Loop
  miAnimatesprite.X +=2;


Bueno, esto es todo por hoy, quizá quedaron cosas en el aire, pero mirando el código fuente, seguro entenderán.



Código fuente de este capítulo para VS 2008, C# 2.0 y SDL.Net 6.1:

//Tutorial de SDL.NET
//Archivo: cap10.cs
//Autor: Dark-N
//Fecha: 13-06-2011
//Capitulo4: Animación básica de Sprites. Ahora usando VS2008 con SDL.NET 6.1

using System;
using System.Drawing;
using SdlDotNet;
using SdlDotNet.Graphics; //para Sprites y surface Video
using SdlDotNet.Core; //Eventos Tick y Quit
using SdlDotNet.Input; //eventos teclado
using SdlDotNet.Graphics.Sprites;  //textos y graficos

namespace tutorial
{	
	public class cap10
	{
		int resx = 640;
		int resy = 480;
		
		Surface hojaSprite;
		AnimatedSprite personaje1 = new AnimatedSprite();
		AnimatedSprite personaje2 = new AnimatedSprite();
		AnimatedSprite personaje3 = new AnimatedSprite();
		AnimatedSprite personaje4 = new AnimatedSprite();
		AnimatedSprite personaje5 = new AnimatedSprite();
		AnimationCollection an1 = new AnimationCollection();
		AnimationCollection an2 = new AnimationCollection();
		AnimationCollection an3 = new AnimationCollection();
		SurfaceCollection caminaDerechaSrfColl;
		Size tamanoFrame = new Size(24, 32); // tamaño de frame en el sprite
		SdlDotNet.Graphics.Font fuente = new SdlDotNet.Graphics.Font("../../fuentes/ARIAL.TTF", 12);
		TextSprite texto1, texto2, texto3, texto4, texto4cont, texto5, texto5cont, texto6, texto6cont;
		
		//tiempos para manejar velocidad de animación
		int ultimoCalculoFrame;	
		int milisegndosPorFrame = 48; // para animación lenta a 20 FPS o 1 frame cada 48 milisegundos
		int cantDelayFramesAnimacion1 = 30; //30 por defecto. En los 3 frames que tiene la hoja de sprites, cada vez que recorre 1, espera 30 milisegundos antes de pasar al siguiente
		int cantDelayFramesAnimacion2 = 90; //90 de delay milisegundos entre cada frame
		int cantDelayFramesAnimacion3 = 10; //10 de delay milisegundos entre cada frame. Se ve caminando muy rápido


		public cap10()
		{
			ultimoCalculoFrame = Timer.TicksElapsed;
			Video.SetVideoMode(resx, resy);			
			Video.WindowCaption = "Tutorial SDL: Capitulo 10 - VS2008 - SDL 6.1";
			
			hojaSprite = new Surface("../../Imagenes/sprite_derecha.png");
    
			// Se crean los Frames de Animación
			caminaDerechaSrfColl = new SurfaceCollection();
			caminaDerechaSrfColl.Add(hojaSprite, tamanoFrame, 0);
			an1.Add(caminaDerechaSrfColl, cantDelayFramesAnimacion1);
			an2.Add(caminaDerechaSrfColl, cantDelayFramesAnimacion2); //animacion para mostrar personaje que anda mas lento, caminando
			an3.Add(caminaDerechaSrfColl, cantDelayFramesAnimacion3); //animacion para mostrar personaje que anda mas rápido
			
			// Agregamos las animaciones al personaje. Se verá corriendo
			personaje1.Animations.Add("CaminaDerecha", an1);
			// Pintamos transparente el fondo del sprite
			personaje1.TransparentColor = Color.Magenta;
			personaje1.Transparent = true;
			personaje1.CurrentAnimation = "CaminaDerecha";
			personaje1.Animate = true;
			
			//personaje 2 se mueve más lento, simulando que camina
			personaje2.Animations.Add("CaminaDerecha", an2);
			personaje2.TransparentColor = Color.Magenta;
			personaje2.Transparent = true;
			personaje2.CurrentAnimation = "CaminaDerecha";
			personaje2.Animate = true;
			
			// personaje 3 se mueve a la derecha más rápido, se ve corriendo
			personaje3.Animations.Add("CaminaDerecha", an1);
			personaje3.TransparentColor = Color.Magenta;
			personaje3.Transparent = true;
			personaje3.CurrentAnimation = "CaminaDerecha";
			personaje3.Animate = true;
			
			// personaje 4 se mueve a la derecha, pero caminando y no corriendo
			personaje4.Animations.Add("CaminaDerecha", an2);
			personaje4.TransparentColor = Color.Magenta;
			personaje4.Transparent = true;
			personaje4.CurrentAnimation = "CaminaDerecha";
			personaje4.Animate = true;
			
			// personaje 5 se mueve a la derecha, pero caminando muy rápido
			personaje5.Animations.Add("CaminaDerecha", an3);
			personaje5.TransparentColor = Color.Magenta;
			personaje5.Transparent = true;
			personaje5.CurrentAnimation = "CaminaDerecha";
			personaje5.Animate = true;
			
			//pocisiones
			personaje1.X = 10; personaje1.Y = 60;
			personaje2.X = 10; personaje2.Y = 140;
			personaje3.X = 0;  personaje3.Y = 210;
			personaje4.X = 0;  personaje4.Y = 290;
			personaje5.X = 0;  personaje5.Y = 370;
		}

		private void Events_Tick(object sender, TickEventArgs e)
		{
			Video.Screen.Fill(Color.Black);
			texto1 = new TextSprite("Ejemplo Animación de un Sprite con distintas velocidades de animación", fuente, Color.Yellow, new Point(0, 5));
			texto2 = new TextSprite("Animación corriendo con un delay de 30 milisegundos antes de pasar al otro frame. Velocidad por defecto.", fuente, Color.White, new Point(0, 40));
			texto3 = new TextSprite("Animación corriendo con un delay de 90 milisegundos antes de pasar al otro frame. Se ve caminado.", fuente, Color.White, new Point(0, 120));
			texto4 = new TextSprite("Movemos Personaje 60 veces por segundo (60 FPS - frames por segundo) o 1 frame cada 16 milisegundos", fuente, Color.White, new Point(0, 180));
			texto4cont = new TextSprite("Además le damos el efecto de que se ve corriendo ya que el delay entre cada frame es de 30 miliseg.", fuente, Color.White, new Point(0, 180 + 12));
			texto5 = new TextSprite("Movemos Personaje 20 veces por segundo (20 FPS - frames por segundo) o 1 frame cada 48 milisegundos", fuente, Color.White, new Point(0, 260));
			texto5cont = new TextSprite("Además le damos el efecto de que se ve camindo ya que el delay entre cada frame es de 90 miliseg.", fuente, Color.White, new Point(0, 260 + 12));
			texto6 = new TextSprite("Movemos Personaje a 60 FPS, con 2 pixels de movimiento y además con un delay de animación de 10 miliseg,", fuente, Color.White, new Point(0, 340));
			texto6cont = new TextSprite("lo que hace que se mueva muy rápido.", fuente, Color.White, new Point(0, 340 + 10));
			
			Video.Screen.Blit(personaje1);
			Video.Screen.Blit(personaje2);
			Video.Screen.Blit(personaje3);
			Video.Screen.Blit(personaje4);
			Video.Screen.Blit(personaje5);
			
			LogicaMovimiento();
			
			Video.Screen.Blit(texto1);
			Video.Screen.Blit(texto2);
			Video.Screen.Blit(texto3);
			Video.Screen.Blit(texto4);
			Video.Screen.Blit(texto4cont);
			Video.Screen.Blit(texto5);
			Video.Screen.Blit(texto5cont);
			Video.Screen.Blit(texto6);
			Video.Screen.Blit(texto6cont);
			
			Video.Screen.Update();
		}


		private void LogicaMovimiento() 
		{
			if (personaje1.Animate)
			{
			    ++personaje3.X;
			}
			
			if (personaje5.Animate)
			{
			    personaje5.X += 2;
			}
			
			if (personaje2.Animate)
			{
			    //solo movemos el personaje si han pasado los frames que establecimos
			    if (Timer.TicksElapsed - ultimoCalculoFrame >= milisegndosPorFrame)
			    {
			        ++personaje4.X;
			        ultimoCalculoFrame = Timer.TicksElapsed;
			    }
			}
		}		

		public void Run()
		{	
			Events.Fps = 60;
			Events.Tick += new EventHandler(this.Events_Tick);
			Events.KeyboardDown += new EventHandler(Events_KeyboardDown);
			Events.Quit += new EventHandler(this.Events_Salir);
			Events.Run();
		}

		private void Events_Salir(object sender, QuitEventArgs e)
		{
			Events.QuitApplication();
		}

		private void Events_KeyboardDown(object sender, KeyboardEventArgs e)
		{
			switch(e.Key)
			{				
				case Key.Escape:
					Events.QuitApplication();
					break;
			}							
		}

		[STAThread]
		public static void Main()
		{
			cap10 juego = new cap10();
			juego.Run();
		}
	}
	
}


Una vez codificado, si al compilar no arroja errores, debe aparecerte algo como esto:



Bajar proyecto para VS 2008 usando SDL.Net 6.1 aquí.



Anterior | Índice
Volver a Página Principal

blog comments powered by Disqus
2003 - 2018    La Web de Dark-N