Artigo
Animando Sprites no XNA
Uma simples abordagem demonstrando como animar Sprites(Sprite Sheet) no XNA
Enviado por Luciano José em 30/12/2008 0:00:00

Introdução
 
Este artigo vai mostrar como animar Sprites(Sprite Sheet) utilizando o XNA Game Studio 3.
 
A animação mostrada aqui consiste na leitura de arquivo de imagem, .PNG por exemplo, contendo vários Sprites(frames) aonde cada frame compõe um estado de um Sprite.
 
Exemplos de estados de Sprites: Idle(Ocioso), Run(Correr), Celebrate(Celebrar), Die(Morrer), Jump(Pular).
 
Esses estados podem ser compostos por no mínimo 1 frame e todos os estados aparecem comumente em 2 situações:
 
  • dispostos no mesmo arquivo de Imagem;
 
  • em arquivos de imagem separados. 
Este artigo vai mostrar a animação de Sprites utilizando arquivos de imagem separados, ou seja, cada estado do Sprite estará em um único arquivo de imagem, como mostra as imagens abaixo:
 
Imagem 1 – Estado: Idle

 
Imagem 2 – Estado: Run
 
Imagem 3 – Estado: Celebrate 
 
Imagem 4 – Estado: Die
 
Imagem 5 – Estado: Jump
 
Lembre-se que você terá plenas condições para também animar Sprites com diferentes estados no mesmo arquivo de Imagem!
 
Início da Programação
 
Iniciando uma breve apresentação do “Demo” que estará disponível para download ao final deste artigo, precisamos definir quais serão os estados do Sprite do nosso jogo, abaixo os estados serão enumerados:
 
    ///<summary>
    /// Sprite State, i.e, Animation´s Type of a Sprite
    ///</summary>
    enum SpriteState
    {
        Celebrate, Die, Idle, Jump, Run
    }
 
Precisamos também de uma estrutura de dado que represente os elementos necessários para a execução da animação, então será definida uma Struct de nome AnimationElement,que vai ter estes campos:
 
        ///<summary>
        /// Animation´s Type of a Sprite
        ///</summary>
        private SpriteState spriteState;
 
        ///<summary>
        /// Image of this Animation
        ///</summary>
        private Texture2D image;
 
        ///<summary>
        /// Indicates how many frames will be drawn at Each 1 second
        ///</summary>
        private int framesPerSecond;
 
        ///<summary>
        /// Count of rows of frames of the Animation´s Image
        ///</summary>
        private int rows;
 
        ///<summary>
        /// Count of Columns of frames of the Animation´s Image
        ///</summary>
        private int columns;
 
        ///<summary>
        /// Regions(rectangles) of the Frames
        ///</summary>
        private List<Rectangle> rectangles;
 
        ///<summary>
        /// Width of the Frame
        ///</summary>
        private int frameWidth; 
 
        ///<summary>
        /// Height of the Frame
        ///</summary>
        private int frameHeight;
 
Para este artigo, utilizaremos uma simples arquitetura aonde teremos a entidade Sprite, útil para os Sprites estáticos – aqueles que não serão animados.
 
Conseqüentemente, teremos uma entidade chamada AnimatedSprite, que servirá para os Sprites animados. Temos o seguinte:
 
class AnimatedSprite : Sprite
 
A classe AnimatedSprite herdando de Sprite.
           
O membro de maior relevância dessa classe(AnimatedSprite) é o método AddAnimationque recebe como parâmetro um AnimationElement.
 
A assinatura do método AddAnimation ficou assim:
 
        ///<summary>
        /// Adds one animation to this Sprite.
        ///</summary>
        ///<param name="animationElement">Indicates the elments of the animation.</param>
        public void AddAnimation(AnimationElement animationElement)
 
Então, para que um Sprite Animado(AnimatedSprite)tenha alguma animação, chamadas ao método AddAnimationdeverão ser feitas!
 
Um exemplo de uso
 
Imagine o seguinte cenário:
 
O meu jogo precisa ter um sprite animado, e ele precisará executar uma animação de celebração(Imagem 3 – Estado: Celebrate). Antes de qualquer coisa, precisamos instanciá-lo:
 
AnimatedSprite mySprite = new AnimatedSprite();
 
E de posse de uma instância, agora podemos “preparar” o nosso elemento de Animação, assim:
 
AnimationElement element = new AnimationElement(SpriteState.Celebrate,
                this.Content.Load<Texture2D>("Celebrate"), 1, 11, 12);

As demais tarefas, como por exemplo, obtenção de todos os frames da animação, fica a cargo do AnimationElement obtê-los! Com um elemento de animação em mão, nós já podemos adicioná-lo à nossa instância “mySprite”:
 
mySprite.AddAnimation(element);
 
Você precisará modificar o estado do sprite(tipo da animação):
 
mySprite.SetState(SpriteState.Celebrate);
 
Por fim, basta efetuar as chamadas aos métodos Update e Draw do Sprite Animado em seus respectivos métodos na classe Game.
 
Entendendo o construtor de um AnimationElement
 
Observe novamente como um AnimationElement foi instanciado:
 
AnimationElement element = new AnimationElement(SpriteState.Celebrate,
                this.Content.Load<Texture2D>("Celebrate"), 1, 11, 12);
 
No 1º parâmetro, nós informamos o estado do Sprite, ou seja, o tipo da animação, neste exemplo escolhemos a de celebração, a seguir, no 2º parâmetro,  foi a imagem com os frames da animação de celebração foi lida. Agora volte para a (Imagem 3 – Estado: Celebrate), abra-a e observe que ela possue 1 linha e 11 colunas, no 3º e 4º parâmetro, e por último, a quantidade de frames por segundo que será desenhada – escolhemos 12 frames por secundo.
 
Considerações Finais
 
O “demo” de animação deste artigo apresenta uma animação de Sprite feita em “Looping infinito”, ou seja, o sprite sempre executará a mesma animação. Entretanto, tenha em mento que existirão momentos em que a animação não precisará executar em “looping”.
 
AnimationElement. Com isso, seria melhor guardar os AnimationElement numa coleção e deixar de utilizar as coleção da classe AnimatedSprite.
 
Ao final você pode “baixar” um simples “Demo” mostrando tudo o que foi abordado acima. O “Demo” possui uma simples intarface aonde você poderá executar/vizualizar várias animações.
 
O “demo” está rodando(testado) em Windows, Xbox 360 e Zune.
 
Concluindo, este artigo teve como objetivo apresentar uma simples visão de como animar um sprite no XNA. Fique a vontade em incrementar/modificar os algoritmos deste “demo”.
 
Imagem 6 – Uma foto do “Demo” disponível para download
 

As imagens 1, 2, 3, 4 e 5 foram retiradas do "Starter Kit" chamado Platformer(starter kit que vem no XNA Game Studio 3).

Após a leitura deste artigo, eu sugiro você baixar o "demo" que eu libero ao final deste artigo. Estude-o e publique suas dúvidas aqui no SharpGames!

Dúvidas, críticas ou sugestões são bem-vindas. Obrigado por sua leitura!

Arquivos Anexados
Animation_of_Sprites Download
Sobre o Autor

lucianoJose
Luciano José
Administrador do SharpGames. Blog: lucianojosefj.spaces.live.com

Clique para avaliar:

Comentários
" Corrigido. vlw :]"
Enviado por lucianoJose em 21/2/2009 16:38:43:
 
" Bom, não sei se alguém reparou, mas tem um pequeno erro, pois nas animações, a última sprite passa muito rápido, configure 1 frame por segundo que vai dar para ver nítidamente :p"
Enviado por Bruno em 21/2/2009 16:00:36:
 
" Esqueci de mencionar que o método Contains da interface IDictionary, não é um "Extension Methods" e para você ter acesso a eles("Extension methods"), você precisa do "using System.Linq". vlw"
Enviado por lucianoJose em 25/1/2009 10:06:17:
 
" Olá AndreBaltieri tudo bem? Você está utilizando o using "using System.Linq" ? Por que esse método ao contrário do que você falou, é um "Extension Methods"... Dê uma olhada aqui http://msdn.microsoft.com/en-us/library/bb910681.aspx Esse método está definido na classe Enumerable. Dê uma olhada aqui: http://msdn.microsoft.com/en-us/library/bb910681.aspx Conclusão, não existe erro de codificação. abraços"
Enviado por lucianoJose em 25/1/2009 9:53:04:
 
" Olá Luciano, parabéns pelo artigo. Estou utilizando VS2008 e XNA 3.0, e notei que tem um pequeno erro na codificação. Na classe SpriteAnimation, você cria um dicionário "private Dictionary animationElements;" e mais abaixo você utiliza o método Keys.Contains "bool result = this.animationElements.Keys.Contains(spriteState);". Porém, este método só existe criamos o dicionário a partir de sua interface, o IDIctionary, então modificando a linha "private Dictionary animationElements;" para "private IDictionary animationElements;" funciona legal. Obrigado pela ajuda e abraços."
Enviado por AndreBaltieri em 24/1/2009 21:05:11:
 
" Show de artigo...Vai levar o prêmio do mês de novo :)"
Enviado por Mopaz em 30/12/2008 19:37:31:
 

Adicione seu Comentário  Voltar
Translator
Logos do XBox 360, XNA e Games For Windows
Copyright 2010 por SharpgamesPolítica de Privacidade  |  Termos de Uso