Gli Spritesheets sono stati usati nei giochi per molto tempo. Giochi classici come Legend of Zelda: A Link to the Past e persino giochi moderni come Cut the Rope li hanno usati. In questo articolo, parleremo di cos'è l'animazione di spritesheet e di come codificarla, e dimostreremo anche come possono essere utilizzati in un gioco di piccole dimensioni. Userò JavaScript per il codice, ma dovresti essere in grado di seguirlo in qualsiasi lingua.
Post correlatiQuesto tutorial fa parte di una collaborazione speciale tra un artista, un animatore e un gamedev!
Prima di poter iniziare a parlare di come codificare un'animazione con uno sprite, dovremmo prima definire alcuni termini: animazione, folletto, e spritesheet.
Post correlatiRisorse aggiuntive che potresti trovare utili:
Nel 1872, Eadweard Muybridge ricevette l'incarico di dimostrare se un cavallo avesse sollevato tutte e quattro le zampe da terra in una sola volta mentre correva. Per farlo, ha installato una serie di telecamere lungo una traccia e ha scattato foto in rapida successione mentre correva un cavallo. Questo processo gli ha permesso di catturare 16 immagini della corsa del cavallo. In una delle immagini, il cavallo aveva effettivamente tutte e quattro le zampe da terra.
Successivamente Muybridge ha ripetuto l'esperimento e posizionato ciascuna foto su un dispositivo in grado di proiettare le foto in rapida successione per dare l'illusione dell'esecuzione del cavallo, creando il primo proiettore cinematografico.
Il processo di modifica delle immagini in rapida successione per dare l'illusione del movimento è chiamato animazione.
Uno sprite è una singola immagine grafica che è incorporata in una scena più grande in modo che sembri essere parte della scena.
Gli sprite sono un modo popolare per creare scene grandi e complesse, dato che puoi manipolare ogni sprite separatamente dal resto della scena. Ciò consente un maggiore controllo su come viene resa la scena, oltre a come i giocatori possono interagire con la scena.
Non è raro che i giochi contengano da decine a centinaia di folletti. Caricare ognuno di questi come un'immagine singola consumerebbe molta memoria e potenza di elaborazione. Per aiutare a gestire gli sprite ed evitare di usare tante immagini, molti giochi usano gli spritesheets.
Se stai cercando una grafica creativa pre-creata, scopri gli sprite e i fogli di gioco che potrebbero essere adatti alle tue esigenze. Oppure puoi ordinare il tuo sprite personalizzato per il gioco su Envato Studio.
Quando metti molti sprite in una singola immagine, ottieni uno sprite.
Gli spritesheets vengono utilizzati per accelerare il processo di visualizzazione delle immagini sullo schermo; È molto più veloce recuperare un'immagine e visualizzare solo una parte di quell'immagine piuttosto che recuperare molte immagini e visualizzarle.
L'animazione di Spritesheet non è altro che prendere un foglio di sprite e cambiare quale sprite è renderizzato in rapida successione per dare l'illusione del movimento, proprio come un film proiettore che visualizza un film.
I fogli di calcolo sono costituiti da due parti: cornici e cicli
Una cornice è una singola immagine (o sprite) dal foglio di sprite. Tornando all'esempio del cavallo di Muybridge, ogni immagine del cavallo nell'immagine sarebbe una cornice.
Quando i frame vengono inseriti in un ordine che crea un movimento continuo, crea un ciclo.
Mettere le foto del cavallo nell'ordine in cui sono state scattate produce un ciclo di "corsa" dal momento che il cavallo sta correndo (al contrario di un ciclo "a piedi" o "inattivo").
Ci sono tre parti per codificare un'animazione di spitesheet:
Inizieremo creando la funzione (o classe) che gestirà l'animazione del foglio di sprite. Questa funzione creerà l'immagine e stabilirà il suo percorso in modo che possiamo usarla per disegnare.
function SpriteSheet (path, frameWidth, frameHeight) var image = new Image (); var framesPerRow; // calcola il numero di frame in una riga dopo che l'immagine carica var self = this; image.onload = function () framesPerRow = Math.floor (image.width / frameWidth); ; image.src = path;
Poiché i fogli di spillo diversi possono avere diverse dimensioni del fotogramma, è necessario passare la larghezza e l'altezza del fotogramma in modo da poter calcolare con precisione quanti fotogrammi si trovano in una riga e in una colonna dell'immagine. Utilizzeremo queste informazioni in seguito per disegnare l'animazione sullo schermo.
È importante che ogni fotogramma dello sprite abbia la stessa larghezza e altezza; altrimenti, disegnare l'animazione sullo schermo è molto difficile.Per aggiornare l'animazione dello sprite, tutto ciò che dobbiamo fare è cambiare la cornice che disegneremo. Di seguito è riportato il foglio sprite diviso in ciascuno dei suoi frame e numerato.
Ad ogni frame del gioco, aggiorneremo il foglio di sprite. Tuttavia, non vogliamo che l'animazione passi al fotogramma successivo ogni fotogramma, quindi dobbiamo dire al nostro sprite quanti fotogrammi attendere prima di passare.
È importante notare che non tutti gli sprite hanno uno sprite in ogni frame disponibile (come ad esempio l'immagine di Muybridge "The Horse in Motion"). Se dovessimo provare ad animare il nostro foglio di sprite con una cornice vuota, ci sarebbe un blip nell'animazione ogni volta che la cornice vuota viene disegnata sullo schermo.
Per compensare questo, diremo anche al foglio di sprite qual è l'ultimo numero di fotogramma, in modo che non animiamo fotogrammi vuoti.
function SpriteSheet (path, frameWidth, frameHeight, frameSpeed, endFrame) // codice rimosso per brevità var currentFrame = 0; // il frame corrente per disegnare var counter = 0; // tiene traccia del frame rate // Aggiorna l'animazione this.update = function () // aggiorna al fotogramma successivo se è il momento if (counter == (frameSpeed - 1)) currentFrame = (currentFrame + 1)% endFrame; // aggiorna il contatore = = (contatore + 1)% frameSpeed; ;
Utilizzando l'operatore modulo (%
) per il currentFrame
, possiamo creare un ciclo continuo ogni volta che endFrame
è raggiunto, il currentFrame
tornerà a 0
, quindi looping dell'animazione.
L'operatore modulo per il contatore impedisce l'overflow dei numeri interi.
Disegnare un'immagine da una scheda sprite funziona nello stesso modo in cui si disegna un'immagine da una mappa di tile.
Calcoliamo la riga dell'immagine che vogliamo disegnare prendendo il modulo del frame corrente e il numero di frame per riga. Calcoliamo la colonna dividendo il fotogramma corrente per il numero di fotogrammi per riga.
Usando questa riga e colonna, possiamo quindi calcolare le coordinate del frame da disegnare moltiplicandole per frameWidth
e frameHeight
, rispettivamente:
// Disegna il frame corrente this.draw = function (x, y) // ottieni la riga e il col del file var row = Math.floor (currentFrame / framesPerRow); var col = Math.floor (currentFrame% framesPerRow); ctx.drawImage (image, col * frameWidth, row * frameHeight, frameWidth, frameHeight, x, y, frameWidth, frameHeight); ;
Con la funzione spitesheet, possiamo ora utilizzarla per creare un'animazione di spitesheet:
spritesheet = new SpriteSheet ('Walk_Cycle_Image.png', 125, 125, 3, 16); function animate () requestAnimFrame (animato); ctx.clearRect (0, 0, 150, 150); spritesheet.update (); spritesheet.draw (12.5, 12.5);
Il codice sopra funzionerà per qualsiasi foglio sprites contenente un ciclo. Tuttavia, non è raro che uno sprite mantenga più cicli, il che significa che ci saranno più animazioni in un singolo sprite.
Dovremo modificare il modo in cui il nostro foglio di sprite funziona per gestire più animazioni da un singolo sprite.
Poiché l'immagine rimane la stessa tra le animazioni, divideremo il nostro sprite in due funzioni: una per l'immagine e una per ogni animazione dal foglio di sprite.
Un foglio sprite terrà le informazioni sull'immagine e le dimensioni della cornice.
function SpriteSheet (path, frameWidth, frameHeight) this.image = new Image (); this.frameWidth = frameWidth; this.frameHeight = frameHeight; // calcola il numero di frame in una riga dopo che l'immagine carica var self = this; this.image.onload = function () self.framesPerRow = Math.floor (self.image.width / self.frameWidth); ; this.image.src = path;
Un'animazione si occuperà dell'aggiornamento e del disegno dello sprite.
function Animation (spritesheet, frameSpeed, startFrame, endFrame) var animationSequence = []; // array contenente l'ordine dell'animazione var currentFrame = 0; // il frame corrente per disegnare var counter = 0; // tiene traccia del frame rate // crea la sequenza di numeri di frame per l'animazione per (var frameNumber = startFrame; frameNumber <= endFrame; frameNumber++) animationSequence.push(frameNumber); // Update the animation this.update = function() // update to the next frame if it is time if (counter == (frameSpeed - 1)) currentFrame = (currentFrame + 1) % animationSequence.length; // update the counter counter = (counter + 1) % frameSpeed; ; // draw the current frame this.draw = function(x, y) // get the row and col of the frame var row = Math.floor(animationSequence[currentFrame] / spritesheet.framesPerRow); var col = Math.floor(animationSequence[currentFrame] % spritesheet.framesPerRow); ctx.drawImage( spritesheet.image, col * spritesheet.frameWidth, row * spritesheet.frameHeight, spritesheet.frameWidth, spritesheet.frameHeight, x, y, spritesheet.frameWidth, spritesheet.frameHeight); ; spritesheet = new SpriteSheet('Walk_Cycle_Image.png', 125, 125); walk = new Animation(spritesheet, 3, 0, 15); function animate() requestAnimFrame( animate ); ctx.clearRect(0, 0, 150, 150); walk.update(); walk.draw(12.5, 12.5);
Poiché il foglio di sprite contiene più fotogrammi di quelli necessari per ogni singola animazione, è necessario conoscere il numero di fotogramma per avviare e terminare l'animazione. Usando queste informazioni, creeremo una serie di numeri di frame in modo che possiamo usarli currentFrame
per accedere al numero di fotogramma corretto.
Con l'animazione pronta per gestire qualsiasi scheda sprite, possiamo utilizzarla per creare un semplice runner infinito in stile Canabalt:
Puoi trovare il codice sorgente completo per questo nel nostro repository GitHub. Qual è il tuo punteggio più alto?
Se stai cercando una grafica di gioco creativa, abbiamo a prezzi accessibili Sprites e Fogli su GraphicRiver, che potrebbero essere proprio la soluzione di cui il tuo gioco ha bisogno. Oppure, se sei interessato a ricevere aiuto con le tue animazioni, Envato Studio ha una fantastica collezione di animatori che ti piacerebbe esplorare.