Animere med aktiva ark Et alternativ til blitting

Så du har ditt fantastiske spill i verkene, det har all slags kompleks fysikk, episk fiende AI eller hva-har-du. Men det føles livløst. Du vil ha noen OOMPH, du vil ha litt animasjon!

Hvis du går og ser opp hvordan du kan animere, vil det første svaret du sannsynligvis være en metode ved hjelp av spritesheets og blitting. Faktisk snakker nesten alle opplæringsprogrammer på nettet om ingenting men blitting, som om det ikke er noen annen måte å animere. Men i min erfaring er det en bedre måte å animere dine orker og goblins på!

Denne metoden kan kalles animerer med eiendomsark - eller mer teknisk, tweening med eiendomsark - i motsetning til bruk sprite-ark. Før vi kommer inn på akkurat hva dette betyr, la oss vurdere et viktig spørsmål:


Hva er galt med blitting?

Nedenfor er det noen grunner til Hvorfor du vil ikke bruke blitting i visse tilfeller.

1. Det tar mye plass

Uansett om vi snakker om RAM- eller diskplass, kan sprite ark lett tette opp ting. Spesielt hvis du prøver å lage HD-grafikk. Store sprite ark må kanskje deles i flere PNGs, ta opp verdifull RAM og skyrocketing ditt spill størrelse hvis du ikke er forsiktig.

2. Det er ikke dynamisk

Hva skjer når du vil fremskynde en animasjon? Du kan hoppe over noen rammer, men hva med å senke? Animasjonen ville se hakket og stygg. Selv om du bare vil støtte 60 fps, hva om en datamaskin kan kjøre spillet raskere? Du kan ha jaw-slippende jevne animasjoner ved høyere bildefrekvenser uten ekstra arbeid, og det vil også se bra ut hvis du velger å endre spillets rammeprosent når som helst.

Og hva om du ville ha noe å skje når spillerens armer nådde noe sted? Eller å få ham til å hente noe? Du må manuelt markere armen gjennom animasjonen, noe som kan være tidkrevende fordi du ikke kan få noen data om hvor noen av hans lemmer er fra et sprite ark.

3. Det tillater deg ikke å gjøre overganger

Hva skjer når spilleren kjører og hopper plutselig? Den kutter til hopp animasjonen med en gang. Dette ser hakket ut, og dette vil skje hver gang animasjonen overgår til en ny stat. Du må gjøre en overgang for hvert par animasjoner du har, som ikke bare er sinnsykt tidskrevende, men har også den negative effekten av å øke RAM-bruken som diskutert tidligere.


Alternativet

Ved bruk av aktivarklader kan ikke bare animasjonene være dynamiske og skalere opp med noen FPS, samt overføre jevnt mellom alle to stater, men også tar en liten liten diskplass og RAM sammenlignet med blitting!

Dette er ikke engang helt ny. Noen populære spill bruker den, som den nylig populære Closure. Den eneste begrensningen er at den ikke kan gjøre ramme-for-ramme-animasjon, siden den er avhengig av tweening - så hvis du har komplekse eksplosjoner, må du bruke sprite ark.

Men for mange tilfeller finner du at du ikke trenger det, og det er mer enn verdt å forsøke å ha et slikt system for ditt spill, da noen spill kan stole helt på dette, barberer en rekke overhead . Det er også veldig kult fordi det ligner på hvordan du kan animere et 3D-spill!

Så for å oppsummere:


La oss dykke rett inn

Dette er et tegn og hans aktivitetsark.

Som navnet antyder, er et aktivark et PNG med alle lemmer / eiendeler av tegnet eller objektet skilt.
Og her er animasjonsdataene i JSON (selvfølgelig kan du bruke hvilket format du foretrekker å jobbe med):

 // denne delen viser de tre første rammene av "Body" animasjonen "-name": "Body", "Frame": ["-x": "0.65", "-y": "- 64.45", " -rotasjon ":" 0.000 "," -x ":" 2.45 "," -y ":" - 64.45 "," -rotasjon ":" 0.279 "," -x ":" 3,30 " y ":" - 64.05 "," -rotasjon ":" 0.707 "

Nå kombinerer disse to sammen i en fantastisk motor, får du:

Og i motsetning til en blitted animasjon, kan dette farten ned eller oppover, eller overgangen veldig jevnt. Så dette er hva vi skal gjøre.


Trinn 1: Eksporter ditt aktivark

Det første trinnet er å få aktivarket klart. Du kan gjøre dette på noen måter. Poenget er å ende opp med et ark som inneholder eiendelene og en datafil som inneholder posisjonene til eiendelene i arket. Dette er nøyaktig samme metode som for å lage et spritesheet, bortsett fra i stedet for sprites, legger du til separate eiendeler.

Eksporter spillerens lemmer og stykker som individuelle PNG, og bruk et program som Texture Packer for å gruppere dem i et ark. Det finnes andre programmer, men jeg personlig foretrekker Texture Packer på grunn av hvor allsidig og funksjonsrik den er.

Tips: Uansett hvilken programvare du bruker til å lage arkene dine, må du sørge for at det er minst 2px polstring mellom hver enkelt ressurs og 1px ekstrudering. Dette vil forhindre noen ekkel problemer i fremtiden.

Trinn 2: Eksportere animasjonsdataene dine

Dette er uten tvil det viktigste trinnet, fordi dette skal være de dataene du bruker til å lage alle animasjonene på kjøretid. Det er også viktig fordi det er plattformuavhengig. Du kan bruke de samme animasjonsdataene på en PS3 som du ville på en iPhone.

Dataene du trenger er x-posisjon, y-posisjon, rotasjonsverdi og andre slike egenskaper for hver ressurs for hver ramme av animasjonen din.

Hvis du bruker Adobe Flash til å animere, kan du enkelt eksportere animasjonsdataene dine. I teorien er alt du trenger å gjøre, løkke gjennom MovieClips barn, og gå gjennom rammene mens du får dataene.

Dette kan imidlertid være et ordensforstyrrelser. Heldigvis finnes det verktøy som gjør dette allerede. For eksempel er Grapefrukt et fantastisk verktøy som har en rekke funksjoner, inkludert eksport av spritesheets samt animasjonsdata i XML.

Merk: Du må sørge for at navnene på dine eiendeler i dataene samsvarer med navnene i aktivarket slik at de enkelt kan kobles sammen.

Hvis du prøver å endre det, eller hvis du bare vil ha den enkle funksjonen ved å eksportere animasjon, kan du velge å bruke min egen animasjonseksportørklasse, som automatisk eksporterer animasjonsdata i en JSON-fil i samme katalog. Du kan laste den ned her, sammen med et eksempelarkiv, og et eksempel på animasjon.

Hvis du bruker annen animasjonsprogramvare (eller din egen), bør det ikke være for vanskelig å finne eller skrive et plugin som eksporterer koordinatene og dataene til eiendelene i hver ramme.

Her er en liste over alle attributter Flash-eksportørene produserer for hver ressurs:

  • x og y
  • rotasjon (i grader eller radianer)
  • scaleX og Scaley (hvor mye aktiva skaleres på hver akse)
  • alfa (Transparens)
  • colorMatrix (lar deg eksportere data som lysstyrke, fargetone og kontrast)

Det er ingen grense for hvor mye data du kan sende ut. For eksempel la jeg til en ekstra dybde feltet i eksportøren min som forteller meg dybden av hver eiendel. Slik at hvis animatoren ordner eiendelene i en bestemt rekkefølge, eller endrer lagene, blir de oppdatert automatisk i motoren.

Så som du kan se, kan du gjøre mange forskjellige typer animasjoner og funksjoner med de riktige dataene.


Trinn 3: Parsing dataene

Så nå har du eiendomsarket ditt, datafilen og animasjonen JSON klar. Deretter kommer den harde delen: skrive animasjonssystemet som forstår våre data og konverterer de separate eiendeler og rådata til vakker animasjon.

Det første trinnet er å laste animasjonsdataene. Dette burde være enkelt siden de fleste språk har en JSON- eller XML-parser.

Deretter skjøter du hver ressurs ut av arket (eller rettere bare gjengir rektangelet med eiendelen din) og lagrer dem i en matrise.

Så nå har våre spillobjekter to arrays: an assetArray som har de faktiske eiendelene, og en animationArray som har animasjonsdataene.

Merk: Du vil kanskje indeksere animationArray og gi eiendelene navnene. Dette er slik at du enkelt kan få tilgang til de riktige dataene fra animasjonsarrangementet - så hvis jeg skriver ut verdien av object.assetArray [5] .name, Jeg vil få "ben", for eksempel. Så hvis jeg går og får tilgang object.animationArray [ "ben"], Jeg burde få animasjonsdataene til tegnets ben.

La oss nå se noen kode!

 /// Inne i objektets oppdateringsfunksjon var animasjonArray: Array = object.animationArray; var assetArray: Array = object.assetArray; // vi løp gjennom alle eiendelene for (var i: int = 0; i < assetArray.length; i++) assetArray[i].x = object.x; assetArray[i].y = object.y; assetArray[i].angle = object.angle; 

Så langt går vi gjennom alle eiendelene for å sette deres x, y og rotasjon til det av moderobjektet. Dette er viktig slik at du kan flytte objekter uten å ødelegge animasjonen, slik at animasjonskoordinatene er i forhold til det punktet.

 /// Inne i objektets oppdateringsfunksjon var animasjonArray: Array = object.animationArray; var assetArray: Array = object.assetArray; // vi løp gjennom alle eiendelene for (var i: int = 0; i 

Her la vi til linjen + animationArray [assetArray [i] .name] [currentFrame] .x, hvor currentFrame er et heltall som representerer den nåværende rammen du er inne i.

Nå vil alle eiendelene være i deres første rammeposisjoner, så en gang du øker currentFrame, de ville være på stillingene i ramme 2, og så videre.

Gratulerer, du har opprettet animasjon! Det ser ut som om du hadde gjort det med et spritesheet, bortsett fra at det bare kostet deg noen få kilobytes i stedet for megabyte.

Dette er bare et veldig enkelt eksempel. Normalt vil du ha separate animasjoner, for eksempel en "kjører" animasjon med 30 rammer, og en "hopp" animasjon med 12 rammer. For å gjøre dette, vil du bare legge til et annet lag i animasjonsmatrisehierarkiet slik at det ser slik ut:


Trinn 4: Interpolering

Vi trenger ikke å stoppe der. Vi vil prøve å gjøre våre animasjoner så glatte og dynamiske som lovet.

Normalt vil dette være noe ganske vanskelig - vi må lagre den komplette tilstanden til den forrige rammen for å kunne interpolere til dagens. Men heldigvis lagrer vårt system allerede denne informasjonen!

Du alltid vet hvor den forrige rammen var, og hvor den neste rammen skal være, så interpolerer mellom rammer er så enkelt som dette:

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

Her får vi forskjellen mellom neste ramme og gjeldende ramme, multiplisert med a timeFactor hvilken er den tid mellom de to rammene.

Dette betyr at i stedet for animasjonen ser slik ut i slowmotion:


... det ville se slik ut:


Ta at, blitting!


Bonus Trinn: Farge Matrix

Hvis du bruker Flash for å animere, kan fargematrisen din se slik ut:

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

Ikke veldig leselig nå er det?

Flash lagrer alle lysstyrke-, kontrast- og metningsdataene der. Heldigvis postet de opp sin formel slik at vi ikke trenger å forsøke å omdanne dette.

Den nedenstående formelen forteller deg hvordan du beregner de endelige RGBA-verdiene til pikselet gitt kildefargen og fargeringsmatrisen (en er fargematrixarrayen):

 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 [15] * srcB) + (a [13] * srcA) + a [14] alfaResult = (a [15] * srcR) + (a [16] * srcG) + ] * srcB) + (a [18] * srcA) + a [19]

Mer informasjon om Flash ColorMatrix klassen finner du her.


Konklusjon og casestudie

Selv om det kan virke litt skummelt i begynnelsen, er denne metoden egentlig Lett å bruke når alt er satt opp, og å sette opp et riktig grunnlag er verdt litt tid og krefter.

Det er ikke å si at denne metoden er ideell for enhver situasjon. Som nevnt tidligere, hvis spillet ditt er avhengig av ramme-for-ramme-animasjon eller ting som ikke kan gjøres med tweening, ville dette egentlig ikke fungere. (Selv om du alltid kan blande og matche metoder.)

Med det sagt, la oss ta en titt på en siste virkelige verden eksempel på bruk av denne metoden.

Dette er en dør:

Den åpner og lukker, og du vil at spilleren ikke skal kunne komme igjennom den.

Det er enkelt, ikke sant? Du vil bare ha en kollisjonskasse bevege seg vertikalt, avhengig av hvor mange rammer gjennom animasjonen er. Problemet er imidlertid at denne animasjonen ikke er lineær: det er litt lett lettelse. Ved å matche kollisjonskassens vertikale posisjon til animasjonens nåværende ramme, vil kollisjonsboksen ikke synkroniseres med animasjonen, slik at ting ser ut som de enten går gjennom døren eller står i tynn luft.

Heldigvis har du x, y, høyde og bredde av den animerte døren aktiva, slik at du kan perfekt synkronisere kollisjonen din!


Blitting vs asset sheets