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
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Generare token per autenicarsi sulle API di GitHub
Recuperare l'ultima versione di una release di GitHub
Usare le collection expression per inizializzare una lista di oggetti in C#
Ottimizzazione dei block template in Angular 17
Generare un hash con SHA-3 in .NET
Cancellare una run di un workflow di GitHub
Definire stili a livello di libreria in Angular
Creazione di componenti personalizzati in React.js con Tailwind CSS
Eseguire query manipolando liste di tipi semplici con Entity Framework Core
Referenziare un @layer più alto in CSS
Proteggere le risorse Azure con private link e private endpoints
Utilizzare Copilot con Azure Cosmos DB