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 MembersLi 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
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Operazioni tra insiemi di array in Javascript
Raggruppamento degli aggiornamenti di dipendenze tra directory in un monorepo con Dependabot
Semplificare la gestione dei modelli con Azure AI Foundry Model Router
Utilizzare i command service nei test con .NET Aspire
Breaking the Legacy Barrier: how to Use AI to Modernize Applications
Gestione opzioni colonna nella Blazor QuickGrid
Blue/Green Release in locale con .NET Aspire
Gestione dei codeowners in GitHub
Canary release con .NET Aspire
From Data to Insight: Exploratory Data Analysis with Python, VS Code and SQL MCP Server
Utilizzare @property per animare nativamente un oggetto HTML tramite CSS
Il nuovo persistent state in Blazor


