[XNA] Animação de Sprites – Parte 3
Eai galera, esta é a penúltima parte do tutorial, mas já com esta etapa você já poderão construir seus objetos ou personagens animados. Neste tutorial iremos criar uma classe chamada AnimatedSprite que irá gerenciar objetos animados, ou seja objetos criados com aquela classe do tutorial passado.
O que está classe realmente faz então, esta classe armazena um dicionário de nomes para chamar cada animação que poderá ser adicionada a ele. O método Update navega entre os quadros da animação atual conforme um intervalo de tempo determinado por cada animação. E o método Draw desenha o objeto.
A classe que gerencia as animações (AnimatedSprite) pode ser vista abaixo.
public class AnimatedSprite
{
#region [ Fields ]
/// <summary>
/// Sprite sheet da imagem animada
/// </summary>
protected Texture2D texture;
/// <summary>
/// Posição do objeto animado no mundo
/// </summary>
public Vector2 Position { get; set; }
/// <summary>
/// Dicionário contendo as animações do personagem
/// </summary>
public Dictionary<string, Animation> Animations
{
get { return this.animations; }
}
private Dictionary<string, Animation> animations = new Dictionary<string, Animation>();
/// <summary>
/// Indice do frame da animação em execução
/// </summary>
public int FrameIndex
{
get { return this.frameIndex; }
}
private int frameIndex = 0;
/// <summary>
/// Nome da animação
/// </summary>
private string animationKey;
public string AnimationKey
{
get { return this.animationKey; }
}
/// <summary>
/// Cor de desenho da imagem
/// </summary>
protected Color color = Color.White;
/// <summary>
/// Rotação da imagem
/// </summary>
protected float rotation = 0.0f;
/// <summary>
/// Origem do desenho
/// </summary>
protected Vector2 origin;
/// <summary>
/// Escala da imagem
/// </summary>
protected float scale = 1.0f;
/// <summary>
/// Efeitos de imagem
/// </summary>
public SpriteEffects Flip
{
get { return this.flip; }
set { this.flip = value; }
}
protected SpriteEffects flip = SpriteEffects.None;
/// <summary>
/// Layer de desenho
/// </summary>
protected float layerDepth = 0.0f;
/// <summary>
/// Tempo decorrido do frame atual da animação
/// </summary>
private float timeElapsed = 0.0f;
/// <summary>
/// Lista com os quadros do sprite sheet
/// </summary>
public List<Rectangle> Frames
{
get { return this.frames; }
}
private List<Rectangle> frames = new List<Rectangle>();
/// <summary>
/// Largura do quadro
/// </summary>
private int frameWidth = 0;
/// <summary>
/// Altura do quadro
/// </summary>
private int frameHeight = 0;
/// <summary>
/// Tamanho do frame
/// </summary>
public Vector2 Size
{
get { return new Vector2(frameWidth, frameHeight); }
}
#endregion
#region [ Constructor ]
/// <summary>
/// Construtor do objeto animado
/// </summary>
/// <param name="texture">Imagem (Sprite Sheet)</param>
/// <param name="columns">Quantidade de colunas</param>
/// <param name="rows">Quantidade de linhas</param>
public AnimatedSprite(Texture2D texture, int columns, int rows)
{
this.texture = texture;
this.Position = new Vector2();
this.frameWidth = texture.Width / columns;
this.frameHeight = texture.Height / rows;
// Cria todos os quadros da imagem
for (int i = 0; i < rows; i++)
for (int j = 0; j < columns; j++)
frames.Add(new Rectangle(j * frameWidth,
i * frameHeight, frameWidth, frameHeight));
this.origin = new Vector2(frameWidth / 2, frameHeight / 2);
}
#endregion
#region [ Update ]
/// <summary>
/// Atualiza a animação do objeto
/// </summary>
/// <param name="gameTime">Tempo de jogo</param>
public void Update(GameTime gameTime)
{
timeElapsed += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (timeElapsed > animations[AnimationKey].Interval)
{
if (animations[AnimationKey].IsLooping)
{
frameIndex = (frameIndex + 1) % animations[AnimationKey].FramesCount;
}
else
{
frameIndex = (int)MathHelper.Min(frameIndex + 1, animations[AnimationKey].FramesCount - 1);
}
timeElapsed = 0.0f;
}
}
#endregion
#region [ Draw ]
/// <summary>
/// Desnha o objeto animado
/// </summary>
/// <param name="spriteBatch"></param>
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture,
Position,
Animations[AnimationKey].Frames[frameIndex],
color,
rotation,
origin,
scale,
flip,
layerDepth);
}
#endregion
#region [ Add Animations ]
/// <summary>
/// Adiciona novas animações
/// </summary>
/// <param name="name">Nome chave da animação</param>
/// <param name="newAnimation">Animação definida</param>
public void AddAnimation(string name, Animation newAnimation)
{
animations.Add(name, newAnimation);
}
#endregion
#region [ Play Animation ]
/// <summary>
/// Inicia ou continua uma animação.
/// </summary>
public void PlayAnimation(string name)
{
// Se a animação for a mesma em execução, não reinicia a animação
if (name == AnimationKey)
return;
// Inicia uma nova animação
this.animationKey = name;
this.frameIndex = 0;
this.timeElapsed = 0.0f;
}
#endregion
}
A classe Game1.cs deve ficar da seguinte forma para testar nosso exemplo.
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
/// <summary>
/// Entrada atual do teclado
/// </summary>
///
KeyboardState keyState = Keyboard.GetState();
/// <summary>
/// Entrada antiga do teclado
/// </summary>
KeyboardState oldKeyState = Keyboard.GetState();
/// <summary>
/// Personagem animado
/// </summary>
AnimatedSprite player;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// Cria o personagem
player = new AnimatedSprite(Content.Load<Texture2D>("claudius"), 6, 4);
// Posiciona o personagem na tela
player.Position = new Vector2(100, 100);
// Baixo
// Cria as animações para baixo
Animation stopedDownAnimation = new Animation(player.Frames, 0, 2);
player.AddAnimation("StopedDown", stopedDownAnimation);
// Cria as animações para baixo andando
Animation walkingDownAnimation = new Animation(player.Frames, 2, 4);
walkingDownAnimation.IsLooping = true;
player.AddAnimation("WalkingDown", walkingDownAnimation);
// Esquerda
// Cria as animações para esquerda
Animation stopeLeftAnimation = new Animation(player.Frames, 6, 2);
player.AddAnimation("StopedLeft", stopeLeftAnimation);
// Cria as animações para esquerda andando
Animation walkingLeftAnimation = new Animation(player.Frames, 8, 4);
walkingLeftAnimation.IsLooping = true;
player.AddAnimation("WalkingLeft", walkingLeftAnimation);
// Cima
// Cria as animações para cima parado
Animation stopedUpAnimation = new Animation(player.Frames, 12, 2);
player.AddAnimation("StopedUp", stopedUpAnimation);
// Cria as animações para cima andando
Animation walkingUpAnimation = new Animation(player.Frames, 14, 4);
walkingUpAnimation.IsLooping = true;
player.AddAnimation("WalkingUp", walkingUpAnimation);
// Direita
// Cria as animações para direita parado
Animation stopedRightAnimation = new Animation(player.Frames, 18, 2);
player.AddAnimation("StopedRight", stopedRightAnimation);
// Cria as animações para direita andando
Animation walkingRightAnimation = new Animation(player.Frames, 20, 4);
walkingRightAnimation.IsLooping = true;
player.AddAnimation("WalkingRight", walkingRightAnimation);
// Inicializa a animação do personagem parado a direita
player.PlayAnimation("StopedRight");
}
protected override void Update(GameTime gameTime)
{
oldKeyState = keyState;
keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.Right))
{
player.PlayAnimation("WalkingRight");
player.Position += new Vector2(60.0f, 0.0f) * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
else if (keyState.IsKeyUp(Keys.Right) && oldKeyState.IsKeyDown(Keys.Right))
{
player.PlayAnimation("StopedRight");
}
else if (keyState.IsKeyDown(Keys.Left))
{
player.PlayAnimation("WalkingLeft");
player.Position += new Vector2(-60.0f, 0.0f) * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
else if (keyState.IsKeyUp(Keys.Left) && oldKeyState.IsKeyDown(Keys.Left))
{
player.PlayAnimation("StopedLeft");
}
else if (keyState.IsKeyDown(Keys.Up))
{
player.PlayAnimation("WalkingUp");
player.Position += new Vector2(0.0f, -60.0f) * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
else if (keyState.IsKeyUp(Keys.Up) && oldKeyState.IsKeyDown(Keys.Up))
{
player.PlayAnimation("StopedUp");
}
else if (keyState.IsKeyDown(Keys.Down))
{
player.PlayAnimation("WalkingDown");
player.Position += new Vector2(0.0f, 60.0f) * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
else if (keyState.IsKeyUp(Keys.Down) && oldKeyState.IsKeyDown(Keys.Down))
{
player.PlayAnimation("StopedDown");
}
// Atualiza o personagem
player.Update(gameTime);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
// Desenha o personagem
player.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
Para ver como ficou o resultado veja o vídeo abaixo.
Se quiser fazer download do código-fonte do tutorial clique aqui.
Abraços galera, os próximos tutoriais serão sobre Camera 2D para começarmos a montar um jogo de plataforma.