Gestire gli sprite animati su Windows Phone 7 con XNA 4

di Davide Guida, in XNA per Windows Phone, UserScript,

In questo script analizzeremo l'implementazione di una semplice classe per la gestione delle animazioni con le spritesheets.

Una spritesheet non è altro che una semplice immagine con all'interno in sequenza tutti gli sprites che comporranno la nostra animazione; per semplicità nel nostro esempio supporremo che abbiano tutti stessa dimensione.

L'idea di base è quella di avere una sorta di "cursore", cioè un rettangolo che identifica lo sprite da usare per il frame corrente, e di farlo scorrere ad intervalli fissi.
Il primo passaggio è procurarci gli assets, nel nostro esempio useremo un'immagine con gli sprites di un'esplosione:


Adesso procediamo con la creazione del progetto: da Visual Studio selezioniamo New Project e creiamo un Windows Phone Game (4.0). Una volta creata la soluzione, aggiungiamo al Content Project la nostra spritesheet:


Adesso aggiungiamo una nuova classe, che chiameremo AnimatedSprite. Iniziamo con la lista dei membri interni della classe:

public class AnimatedSprite
{
  #region Members

  private Texture2D _spritesheet = null;

  private float _frameInterval = 50f;
  private Point _spriteSize = Point.Zero;
  private Vector2 _spriteCenter = Vector2.Zero;
  
  private Rectangle _sourceRect;       

  private int _numFrames = 0;
  private float _timer = 0f;
  private int _currentFramePosX = 0;
  private int _currentFramePosY = 0;
  private int _currentFrame = 0;        

  private bool _isAnimationEnded = false;
  private bool _isLooping = true;      

  #endregion Members

Li analizzeremo passo passo. Procediamo con il costruttore:

public AnimatedSprite(Texture2D spriteSheet, Point size, float interval)
{
  if (null == spriteSheet)
    throw new ArgumentNullException("Texture2D");
      
  _spritesheet = spriteSheet; // la nostra spritesheet
  _frameInterval = interval; // l'intervallo in millisecondi tra i frames
  _spriteSize = size; // questa sarà la dimensione di un singolo sprite

  // memorizziamo il punto centrale di un singolo sprite
  _spriteCenter.X = (float)_spriteSize.X * 0.5f;
  _spriteCenter.Y = (float)_spriteSize.Y * 0.5f;

  // e calcoliamo il numero totale dei frames
  _numFrames = (_spritesheet.Width / _spriteSize.X) * 
      (_spritesheet.Height / _spriteSize.Y);
}


Ed ora eccoci al metodo più importante, che ci consente l'aggiornamento dell'animazione:

public void Update(GameTime gameTime)
{
  // Controlliamo che il numero di frames sia sufficiente 
  // e che l'animazione non sia terminata
  if (_numFrames < 2 || (_isAnimationEnded && !_isLooping))
    return;

  float deltaTime = (float)gameTime.ElapsedGameTime.TotalMilliseconds;

  // aggiorniamo il contatore dei millisecondi
  _timer += deltaTime;

  // e se abbiamo superato la soglia di aggiornamento
  if (_timer > _frameInterval)
  {
    // passiamo al frame successivo               
       _currentFrame++;

    // siamo giunti al termine?
    _isAnimationEnded = _currentFrame > _numFrames;

    // se l'animazione è in loop ed è terminata resettiamo tutto
    if (_isLooping && _isAnimationEnded)
    {
      _currentFramePosX = 0;
      _currentFramePosY = 0;
      _currentFrame = 0;
      _isAnimationEnded = false;
    }
    else if (!_isAnimationEnded)
    {
      // altrimenti aggiorniamo la posizione del "cursore" sulla spritesheet
      _currentFramePosX++;
      int x = _currentFramePosX * _spriteSize.X;
      if (x >= _spritesheet.Width)
      {
        // controlliamo che non esca fuori dai bordi della spritesheet
        x = 0;
        _currentFramePosX = 0;
        _currentFramePosY++;
      }
      int y = _currentFramePosY * _spriteSize.Y;
      _sourceRect = new Rectangle(x, y, _spriteSize.X, _spriteSize.Y);
    }

    // infine azzeriamo il timer e siamo pronti per un nuovo frame
    _timer = 0f;
  }
}

Infine, ecco il metodo Render, molto semplice, che non fa altro che disegnare lo sprite corrente usando le impostazioni di posizione, rotazione e scaling passate nella firma:

public void Draw(SpriteBatch spriteBatch, Vector2 position, float angle, 
                 Vector2 scale, Color color)
{
spriteBatch.Draw(_spritesheet, position, _sourceRect, color, angle,
                 _spriteCenter, scale, SpriteEffects.None, 0);
}

Per poter visualizzare l'animazione, non dobbiamo far altro che creare un'istanza della classe all'interno del metodo LoadContent del nostro Game, aggiornarla nel metodo Update ed infine procedere al rendering nel metodo Draw:

_animSprite = new AnimatedSprite(Content.Load<Texture2D>(@"explosion"), new Point(64, 64),                  50f);

_animSprite.Update(gameTime);

spriteBatch.Begin();
_animSprite.Draw(spriteBatch, _position, 0f, _scale, Color.White);
spriteBatch.End();

Ed è tutto!
In allegato troverete un progetto di test creato con Visual Studio 2010 per Windows Phone ed XNA 4, ma la soluzione presentata può essere usata senza problemi anche in contesto Windows o Xbox 360.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi