Uno sprite è un'immagine bidimensionale che rappresenta un personaggio, un nemico, un oggetto o un effetto. Per animarlo si mostrano in rapida successione immagini leggermente diverse, come in un flipbook. Invece di salvare ogni fotogramma in un file separato, i giochi raccolgono le immagini in una sprite sheet: un'unica immagine che contiene tutti i fotogrammi disposti in una griglia o impacchettati in modo compatto.
Perché una sola immagine
Caricare e disegnare decine di file separati è inefficiente per due motivi:
- gestione delle risorse: un file solo si carica più rapidamente e si organizza meglio;
- rendering: la scheda grafica lavora meglio quando molti sprite condividono la stessa texture, perché può disegnarli in un'unica chiamata (batching) senza cambiare continuamente stato.
Disegnare un fotogramma significa quindi copiare sullo schermo solo un rettangolo della sprite sheet, individuato dalle sue coordinate sorgente.
Griglia regolare o atlante impacchettato
Griglia regolare
Ogni fotogramma occupa una cella delle stesse dimensioni, per esempio 32 × 32 pixel. Il rettangolo del fotogramma n si calcola con una semplice divisione:
colonne = larghezza_immagine / larghezza_cella
sx = (n % colonne) * larghezza_cella
sy = (n / colonne) * altezza_cella // divisione intera
È il formato più semplice da creare e leggere, ideale per la pixel art con personaggi di dimensioni costanti.
Atlante impacchettato
Quando gli sprite hanno dimensioni molto diverse, una griglia spreca spazio. Gli strumenti di texture packing dispongono le immagini in modo compatto, eliminano i bordi trasparenti e producono un file di metadati, spesso in JSON, con nome, posizione e dimensioni di ogni fotogramma. Poiché il ritaglio del bordo trasparente sposta l'immagine, i metadati includono anche l'offset da applicare per disegnarla nella posizione corretta.
Problemi tecnici da conoscere
Sbavature tra fotogrammi
Con il filtro bilineare o con coordinate non intere, la scheda grafica può campionare pixel del fotogramma vicino, creando sottili linee colorate ai bordi. Le contromisure classiche:
- lasciare uno spazio vuoto di uno o due pixel tra i fotogrammi (padding);
- ripetere il colore del bordo nell'area di separazione (extrusion);
- per la pixel art, usare il filtro nearest neighbor e disegnare a coordinate intere.
Punto di ancoraggio
Ogni sprite ha un'origine, il punto che corrisponde alla posizione dell'oggetto nel mondo. Per un personaggio conviene di solito il centro dei piedi: così fotogrammi di altezze diverse restano appoggiati al suolo e il ribaltamento orizzontale non sposta la figura.
Ribaltamento
Spesso si disegnano solo le animazioni verso destra e si ribaltano orizzontalmente per la sinistra, dimezzando il lavoro. Attenzione però ai dettagli asimmetrici, come una spada sempre nella mano destra o una scritta su una maglietta.
Temporizzare l'animazione
Un'animazione è una sequenza di fotogrammi con una durata. La versione più semplice usa una frequenza costante:
tempo += dt
fotogramma = floor(tempo * fps_animazione) % numero_fotogrammi
Il valore di fps_animazione è indipendente dal frame rate del gioco: molte animazioni in pixel art usano frequenze tra 8 e 12 fotogrammi al secondo, mentre il gioco gira a 60. Una frequenza bassa non è un difetto ma una scelta estetica.
Gli strumenti di animazione permettono anche durate diverse per ogni fotogramma, molto utili per dare ritmo: in un attacco, la preparazione può durare a lungo, il colpo pochissimo e il ritorno di nuovo più a lungo. Il risultato è molto più leggibile e incisivo di una sequenza a ritmo costante.
Animazioni in loop e animazioni singole
Bisogna distinguere tra:
- animazioni cicliche: camminata, corsa, inattività, che ricominciano dall'inizio;
- animazioni singole: attacco, morte, atterraggio, che si fermano sull'ultimo fotogramma o restituiscono il controllo a un'altra animazione.
Per le animazioni singole è utile emettere un evento al termine, o in un fotogramma preciso. Il danno di un attacco, per esempio, dovrebbe essere applicato nel fotogramma in cui l'arma colpisce visivamente, non all'inizio dell'animazione.
Collegare animazione e stato
L'animazione da mostrare dipende dallo stato del personaggio:
| Stato | Animazione | Tipo |
|---|---|---|
| Fermo a terra | Inattività | Ciclica |
| In movimento a terra | Corsa | Ciclica |
| Velocità verticale negativa | Salto | Singola o ciclica breve |
| Velocità verticale positiva | Caduta | Ciclica |
| Attacco in corso | Attacco | Singola, con evento |
Un errore frequente è riavviare l'animazione a ogni fotogramma perché la si imposta di continuo: occorre cambiarla solo quando lo stato cambia davvero, conservando il tempo trascorso in quella corrente.
Flusso di lavoro con gli artisti
Accordarsi presto su alcune convenzioni evita molto lavoro ripetuto: dimensione delle celle, posizione del punto di ancoraggio, nomi delle animazioni, ordine dei fotogrammi, palette. Molti editor per pixel art esportano direttamente sprite sheet con metadati, che il codice può leggere senza intervento manuale. Così un artista può modificare un'animazione e vederla nel gioco senza toccare il codice.
In sintesi
- Una sprite sheet raccoglie tutti i fotogrammi in una sola immagine, più efficiente da caricare e disegnare.
- La griglia regolare è semplice; l'atlante impacchettato risparmia spazio ma richiede metadati.
- Padding, extrusion e coordinate intere evitano sbavature ai bordi.
- La frequenza dell'animazione è indipendente da quella del gioco e può variare per fotogramma.
- L'animazione va cambiata solo quando cambia lo stato, usando eventi per i momenti chiave.