Animazione con fogli di asset un'alternativa al blitting

Quindi hai in serbo il tuo fantastico gioco, ha tutti i tipi di fisica complessa, un'IA epica del nemico o che cosa hai. Ma sembra senza vita. Vuoi un po 'di OOMPH, vuoi un po' di animazione!

Se andate a cercare come animare, la prima risposta che incontrerete sarà molto probabilmente un metodo che usa gli spritesheets e il blitting. In effetti, quasi tutti i tutorial sul web parlano di niente ma blitting, come se non ci fosse altro modo di animare. Ma nella mia esperienza, c'è un modo migliore per animare i tuoi orchi e goblin!

Questo metodo potrebbe essere chiamato animare con le schede delle risorse - o più tecnicamente, interpolazione con asset-sheet - invece di usare folletto-fogli. Prima di capire esattamente cosa significa, prendiamo in considerazione una domanda importante:


Cosa c'è di sbagliato con Blitting?

Di seguito sono riportati alcuni motivi perché non si vorrebbe usare il blitting in alcuni casi.

1. Prende molto spazio

Sia che si parli di RAM o di spazio su disco, i fogli di sprite possono facilmente intasare le cose. Soprattutto se stai cercando di realizzare una grafica HD. Enormi fogli di sprite potrebbero dover essere suddivisi in più PNG, occupando preziosa RAM e aumentando di molto le dimensioni del tuo gioco se non stai attento.

2. Non è dinamico

Cosa succede quando vuoi velocizzare un'animazione? Potresti saltare alcuni fotogrammi, ma che dire del rallentamento? L'animazione sembrerebbe mossa e brutta. Anche se vuoi supportare solo 60 fps, cosa succede se un computer può eseguire il gioco più velocemente? Potresti avere animazioni incredibilmente fluide a frame rate più alti senza lavoro extra, e sarebbe anche bello se decidessi di cambiare la frequenza fotogrammi del gioco in qualsiasi momento.

E se volessi che succedesse qualcosa quando le braccia del giocatore raggiungevano un posto? O per fargli prendere qualcosa? Dovresti contrassegnare manualmente il braccio durante l'animazione, il che potrebbe richiedere molto tempo poiché non puoi ottenere dati su dove uno qualsiasi dei suoi arti proviene da un foglio di sprite.

3. Non ti consente di effettuare transizioni

Cosa succede quando il giocatore è in esecuzione e salta improvvisamente? Taglia subito l'animazione del salto. Questo sembra mosso, e questo accadrebbe ogni volta che l'animazione passa a un nuovo stato. Dovresti effettuare una transizione per ogni coppia di animazioni che hai, il che non è solo follemente il tempo, ma ha anche l'effetto negativo di aumentare l'utilizzo della RAM come discusso in precedenza.


L'alternativa

L'utilizzo delle schede delle risorse non solo consente alle animazioni di essere dinamiche e scalare con qualsiasi FPS, oltre a passare senza problemi tra due stati, ma anche prende una piccola quantità di spazio su disco e RAM rispetto al blitting!

Questo non è nemmeno molto nuovo. Alcuni giochi popolari lo usano, come la Closure recentemente popolare. La sua unica limitazione è che non può fare animazioni frame-by-frame (FBF), dal momento che si basa sull'interpolazione - quindi se hai esplosioni complesse, dovrai usare i fogli sprite.

Ma per un sacco di casi, scoprirai che non ne avrai bisogno, e vale la pena di avere un sistema come questo per il tuo gioco, dato che alcuni giochi potrebbero fare affidamento su questo, eliminando un sacco di spese generali . È anche molto interessante perché è simile a come potresti animare un gioco 3D!

Quindi per riassumere:


Let's Dive Right In

Questo è un personaggio e il suo foglio dei beni.

Come suggerisce il nome, un foglio di asset è un PNG con tutti gli arti / le risorse del personaggio o dell'oggetto separati.
Ed ecco i dati di animazione in JSON (ovviamente, puoi usare qualsiasi formato tu preferisca lavorare):

 // questo frammento mostra i primi tre fotogrammi dell'animazione "Body" "-name": "Body", "Frame": ["-x": "0.65", "-y": "- 64.45", " -rotation ":" 0.000 ", " -x ":" 2.45 "," -y ":" - 64.45 "," -rotation ":" 0.279 "," -x ":" 3.30 "," - y ":" - 64.05 "," -rotation ":" 0.707 "

Ora combinando questi due insieme in un motore fantastico, ottieni:

E a differenza di un'animazione blitta, questo potrebbe accelerare o aumentare o passare senza intoppi. Quindi questo è quello che faremo.


Passaggio 1: esportazione del foglio delle risorse

Il primo passo è quello di preparare la tua scheda degli asset. Puoi farlo in molti modi. Il punto è finire con un foglio contenente le risorse e un file di dati contenente le posizioni delle risorse nel foglio. Questo è lo stesso metodo utilizzato per creare uno sprite, eccetto che per gli sprite che aggiungi asset separati.

Esporta gli arti e i pezzi del tuo giocatore come PNG individuali, quindi usa un programma come Texture Packer per raggrupparli in un foglio. Ci sono altri programmi, ma personalmente preferisco Texture Packer per via di quanto sia versatile e ricco di funzionalità.

Mancia: Qualunque sia il software che utilizzi per creare i tuoi fogli, assicurati che ci sia almeno 2px di padding tra ogni risorsa e 1px estrusione. Ciò impedirà alcuni problemi sgradevoli in futuro.

Passaggio 2: esportazione dei dati di animazione

Questo è probabilmente il passo più importante, perché saranno i dati che utilizzerai per creare tutte le animazioni in fase di esecuzione. È anche importante perché è indipendente dalla piattaforma. Puoi utilizzare gli stessi dati di animazione su una PS3 come faresti su un iPhone.

I dati di cui hai bisogno sono la posizione x, la posizione y, il valore di rotazione e altre proprietà di ogni risorsa per ogni fotogramma dell'animazione.

Se stai usando Adobe Flash per animare, puoi facilmente esportare i tuoi dati di animazione. In teoria, tutto ciò che devi fare è passare in rassegna i figli di MovieClip e scorrere i fotogrammi mentre ricevi i dati.

Tuttavia, questo può essere un fastidio. Per fortuna, ci sono strumenti che lo fanno già. Ad esempio, Grapefrukt è uno strumento fantastico che ha una varietà di funzionalità, tra cui esportare fogli di calcolo e dati di animazione in XML.

Nota: È necessario assicurarsi che i nomi delle risorse nei dati corrispondano ai nomi nella scheda delle risorse in modo che possano essere facilmente collegati.

Se si sta tentando di modificarlo o se si desidera semplicemente la semplice funzionalità di esportazione dell'animazione, è possibile scegliere di utilizzare la mia classe di esportazione dell'animazione, che esporta automaticamente i dati di animazione in un file JSON nella stessa directory. Puoi scaricarlo qui, insieme a un foglio di asset di esempio e ad un'animazione di esempio.

Se stai usando un altro software di animazione (o il tuo), non dovrebbe essere troppo difficile trovare o scrivere un plugin che esporti le coordinate e i dati delle risorse in ogni frame.

Ecco un elenco di tutti gli attributi che gli esportatori di Flash producono per ogni risorsa:

  • X e y
  • rotazione (in gradi o radianti)
  • scaleX e scaleY (quanto l'asset viene ridimensionato su ciascun asse)
  • alfa (trasparenza)
  • ColorMatrix (consente di esportare dati come luminosità, tonalità e contrasto)

Non c'è limite alla quantità di dati che puoi produrre. Ad esempio, ho aggiunto un extra profondità campo nel mio esportatore che mi dice la profondità di ogni risorsa. In questo modo, se l'animatore dispone le risorse in un determinato ordine o modifica i livelli, vengono aggiornati automaticamente nel motore.

Quindi, come puoi vedere, puoi fare un sacco di diversi tipi di animazioni e funzionalità con i dati giusti.


Passaggio 3: analisi dei dati

Così ora hai la tua scheda patrimoniale, il suo file di dati e l'animazione JSON pronta. Poi arriva la parte difficile: scrivere il sistema di animazione che capisce i nostri dati e converte le risorse separate e i dati grezzi in bellissime animazioni.

Il primo passo è caricare i dati di animazione. Questo dovrebbe essere facile poiché la maggior parte delle lingue ha un parser JSON o XML.

Quindi unisci ogni risorsa fuori dal foglio (o meglio, rendi solo il rettangolo con il tuo asset) e memorizzali in un array.

Quindi ora i nostri oggetti di gioco hanno due array: an assetArray che ha le risorse effettive e un animationArray che ha i dati di animazione.

Nota: Potresti voler indicizzare il animationArray e dare i nomi delle risorse. In questo modo è possibile accedere facilmente ai dati corretti dall'array di animazione, quindi se stampo il valore di object.assetArray [5] .name, Mi piacerebbe avere "gamba", per esempio. Quindi se vado ad accedere object.animationArray [ "gamba"], Dovrei ottenere i dati di animazione per la gamba del personaggio.

Ora vediamo un po 'di codice!

 /// All'interno della funzione di aggiornamento dell'oggetto var animationArray: Array = object.animationArray; var assetArray: Array = object.assetArray; // passiamo in rassegna tutte le risorse per (var i: int = 0; i < assetArray.length; i++) assetArray[i].x = object.x; assetArray[i].y = object.y; assetArray[i].angle = object.angle; 

Finora stiamo collegando tutte le risorse per impostarle X, y e rotazione a quello dell'oggetto madre. Questo è importante per far muovere gli oggetti senza rovinare l'animazione, in modo che le coordinate dell'animazione siano relative a quel punto.

 /// All'interno della funzione di aggiornamento dell'oggetto var animationArray: Array = object.animationArray; var assetArray: Array = object.assetArray; // passiamo in rassegna tutte le risorse per (var i: int = 0; i 

Qui abbiamo aggiunto la linea + animationArray [assetArray [i] .name] [currentFrame] .x, dove currentFrame è un numero intero che rappresenta il frame corrente in cui ti trovi.

Ora tutte le risorse si troverebbero alle prime posizioni del frame, quindi una volta incrementato currentFrame, sarebbero nelle posizioni di Frame 2 e così via.

Congratulazioni, hai creato l'animazione! Sembra identico a come se lo avessi fatto con uno spritesheet, tranne che costa solo qualche kilobyte invece di megabyte.

Questo è solo un esempio molto semplice. Normalmente ti piacerebbe avere animazioni separate, come un'animazione "in esecuzione" con 30 fotogrammi e un'animazione "salta" con 12 fotogrammi. Per fare ciò basta aggiungere un altro livello alla gerarchia dell'array di animazione in modo che assomigli a questo:


Passaggio 4: interpolazione

Non dobbiamo fermarci qui. Vogliamo provare a rendere le nostre animazioni fluide e dinamiche come promesso.

Normalmente questo sarebbe qualcosa di piuttosto difficile - dovremmo memorizzare lo stato completo del frame precedente al fine di interpolare alla corrente. Ma per fortuna, il nostro sistema memorizza già tali informazioni!

tu sempre sapere dove si trovava il fotogramma precedente e dove sarà il fotogramma successivo, quindi interpolare tra fotogrammi è semplice come questo:

 var data: Array = animationArray [assetArray [i] .name] var X: Number = data [currentFrame] .x + (data [currentFrame + 1] .x - data [currentFrame] .x) * _timeFactor; assetArray [i] .x = object.x + X

Qui otteniamo la differenza tra il fotogramma successivo e il fotogramma corrente, moltiplicato per a TimeFactor qual è tempo tra i due fotogrammi.

Ciò significa che al posto della tua animazione sembra così al rallentatore:


... sembrerebbe questo:


Prendere quello, copiarlo sul video!


Bonus Step: Color Matrix

Se stai usando Flash per animare, la tua matrice di colori potrebbe essere simile a questa:

1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0

Adesso non è molto leggibile?

Flash memorizza tutti i dati di luminosità, contrasto e saturazione. Per fortuna, hanno pubblicato la loro formula in modo da non dover provare a decodificare questo.

La seguente formula ti spiega come calcolare i valori RGBA finali del pixel in base al colore sorgente e alla matrice colore (un è l'array matrix a colori):

 redResult = (a [0] * srcR) + (a [1] * srcG) + (a [2] * srcB) + (a [3] * srcA) + a [4] greenResult = (a [5] * srcR) + (a [6] * srcG) + (a [7] * srcB) + (a [8] * srcA) + a [9] blueResult = (a [10] * srcR) + (a [11] * srcG) + (a [12] * srcB) + (a [13] * srcA) + a [14] alphaResult = (a [15] * srcR) + (a [16] * srcG) + (a [17 ] * srcB) + (a [18] * srcA) + a [19]

Ulteriori informazioni su Flash ColorMatrix la classe può essere trovata qui.


Conclusione e case study

Anche se all'inizio potrebbe sembrare un po 'spaventoso, questo metodo è veramente facile da usare quando tutto è impostato, e la creazione di una base adeguata vale la pena un po 'di tempo e fatica.

Questo non vuol dire che questo metodo è l'ideale per ogni situazione. Come accennato in precedenza, se il tuo gioco fa affidamento sull'animazione fotogramma per fotogramma o su cose che non possono essere eseguite con l'interpolazione, allora questo non funzionerebbe. (Anche se potresti sempre mescolare e abbinare i metodi.)

Detto questo, diamo un'occhiata a un esempio reale del mondo reale dell'uso di questo metodo.

Questa è una porta:

Si apre e si chiude e tu vuoi che il giocatore non riesca a superarlo.

È semplice, giusto? Avresti solo una casella di collisione spostare verticalmente, a seconda di quanti fotogrammi attraverso l'animazione è. Il problema, tuttavia, è che questa animazione non è lineare: c'è un leggero allentamento. Abbinare la posizione verticale della scatola di collisione al fotogramma corrente dell'animazione renderebbe la scatola di collisione non sincronizzata con l'animazione, facendo apparire le cose come se passassero attraverso la porta o rimanessero in piedi nell'aria sottile.

Per fortuna, hai il X, y, altezza e larghezza della risorsa porta animata, che consente di sincronizzare perfettamente la tua collisione!


Blitting vs asset sheet