Vamos aprender XNA? – Parte 20 – Simple Model Animation

Publicado em 05/11/2011

3


Olá pessoal, tudo certo?!

Depois de alguns dias falando sobre fractais, html5 e muito JavaScript, volto a escrever código em C# seguindo esta série sobre XNA. Hoje, nada de HLSL, só C#!

Neste post, mostro uma técnica simples de animação (sem intevenção do usuário). Embora esteja utilizando modelos 3D, a mesma técnica pode ser aplicada a sprites.

O código-fonte completo dessa série está disponível em https://github.com/ElemarJR/VamosAprenderXNA

O que vamos fazer?

No post de hoje, uso como ponto de partida o código da parte 07. O objetivo é fazer com que nossa “nave ande de um lado para o outro” repetidamente. Observe:

image

image

image

image

Fica muito mais fácil de entender o que está ocorrendo se você baixar os fontes e rodar o programa.

A classe ModelAnimation

Para realizar a animação, bastava “cuidar da atualização” das propriedades Position e Rotation do modelo 3d (a nave). Por isso, precisamos de um objeto que mantenha:

  • as posições inicial e final que desejamos respeitar em nossa animação;
  • as rotações inicial e final que desejamos respeitar em nossa animação;
  • o tempo total de animação (em um período, desconsiderando looping e reverse);
  • se desejamos que a animação ocorra em “looping” (sem parar);
  • se desejamos executar uma animação oposta (autoreverse).

Esse mesmo objeto deve “calcular” posição e rotação atualizadas conforme o tempo avança. Eis minha implementação:


              
public class ModelAnimation
{
    public Vector3 StartPosition { get; private set; }
    public Vector3 StartRotation { get; private set; }

    public Vector3 EndPosition { get; private set; }
    public Vector3 EndRotation { get; private set; }

    public Vector3 Position { get; private set; }
    public Vector3 Rotation { get; private set; }

    public TimeSpan Duration { get; private set; }
    public bool Looping { get; private set; }
    public bool AutoReverse { get; private set; }

    TimeSpan elapsedTime = TimeSpan.FromSeconds(0);

    public ModelAnimation(
        Vector3 startposition,
        Vector3 startrotation,
        Vector3 endposition,
        Vector3 endrotation,
        TimeSpan duration,
        bool looping,
        bool autoreverse
        )
    {
        this.StartPosition = startposition;
        this.StartRotation = startrotation;
        this.EndPosition = endposition;
        this.EndRotation = endrotation;
        this.Duration = duration;
        this.Looping = looping;
        this.AutoReverse = autoreverse;
    }

    bool reversing = false;
    public void Update(TimeSpan elapsed)
    {
        this.elapsedTime += elapsed;

        var amount = (float)this.elapsedTime.TotalSeconds / (float)Duration.TotalSeconds;

        if (this.Looping)
        {
            if (amount > 1)
            {
                this.elapsedTime = TimeSpan.FromSeconds(0);
                reversing = !reversing;
                while (amount > 1) amount--;
            }
        }
        else
            amount = MathHelper.Clamp(amount, 0f, 1f);

        if (this.AutoReverse && reversing) amount = 1 - amount;

        Position = Vector3.Lerp(this.StartPosition, this.EndPosition, amount);
        Rotation = Vector3.Lerp(this.StartRotation, this.EndRotation, amount);

    }
}

            

Como você pode perceber, a “mágica” acontece dentro do método update. Perceba:

  • calculo uma “quantidade” de animação considerando a razão entre o tempo total transcorrido e o duração programada;
  • estando em looping , verifico a conclusão da animação (um ciclo). Em caso positivo, ligo um flag que “inverte” o amount causando a “inversão” de sentido;
  • Utilizo a função utilitária Lerp para determinar a interpolação linear entre os vetores de início e fim, usando o amount calculado.

Configurando e executando a animação

Configurar a animação é muito simples. Basta criar uma instância de nossa classe no game, informando os parâmetros adequadamente. Observe:


              
animation = new ModelAnimation(
    spaceship.Position,
    Vector3.Zero,
    spaceship.Position + new Vector3(0, 0, 2600),
    new Vector3(0, MathHelper.Pi, 0),
    TimeSpan.FromSeconds(5),
    true,
    true
    );

            

Como pode perceber, determino que :

  • a posição e rotação inicial devem ser iguais ao objeto que estamos animando (nossa nave);
  • a posição final está a 2600 unidades na frente da posição atual;
  • a rotação final será 90 graus no eixo y;
  • o tempo de um ciclo será de cinco segundos;
  • a animação ocorrerá em looping;
  • haverá AutoRevese;

Para garantir que a animação ocorra, falta apenas atualizar o método Update. Perceba:


              
protected override void Update(GameTime gameTime)
{
    base.Update(gameTime);
    animation.Update(gameTime.ElapsedGameTime);
    spaceship.Position = animation.Position;
    spaceship.Rotation = animation.Rotation;
}

            

Pronto!

Era isso.

Smiley piscando

Etiquetado:,
Publicado em: Post