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
Disabilitare le run concorrenti di una pipeline di Azure DevOps
Utilizzare DeepSeek R1 con Azure AI
Personalizzare le pagine di errore su Azure App Service
Abilitare .NET 10 su Azure App Service e Azure Functions
Utilizzare Intersect e Except per filtrare set di dati in TSql
Abilitare automaticamente il force push di un gruppo su Azure DevOps
Integrare modelli AI in un workflow di GitHub
Arricchire l'interfaccia di .NET Aspire
Creare comandi nella dashboard .NET Aspire
Raggruppare risorse in .NET Aspire
Integrazione di Copilot in .NET Aspire
Utilizzare l'espressione if inline in una pipeline di Azure DevOps


