En introduksjon til Spritesheet Animation

Spritesheets har vært brukt i spill i lang tid. Klassiske spill som Legend of Zelda: En kobling til fortiden og til og med moderne spill som Cut the Rope har brukt dem. I denne artikkelen snakker vi om hva spritesheet-animasjon er og hvordan du kodes det, og vi vil også demonstrere hvordan de kan brukes i et lite spill. Jeg bruker JavaScript til koden, men du bør kunne følge med på hvilket som helst språk.

Relaterte innlegg

Denne opplæringen er en del av et spesielt samarbeid mellom en artist, en animator og en gamedev!

  • Kunst av Mary Winkler
  • Animasjon av Adam Everett Miller
  • Gamedev av Steven Lambert

Truffet Rom å hoppe.

Før vi kan begynne å snakke om hvordan å kode en spritesheet-animasjon, bør vi først definere et par vilkår: animasjon, sprite, og spritesheet.

Relaterte innlegg

Ytterligere ressurser du kan finne nyttige:

  • Animere med aktiva ark: Et alternativ til blitting
  • 10 Great Full Game Sprite Sheets fra GraphicRiver
  • Opprette Sprite Sheets i fem minutter med Texture Packer

animasjon

Tilbake i 1872 ble Eadweard Muybridge bestilt for å bevise om en hest løftet alle fire beina av bakken på en gang da den løp. For å gjøre det, satte han opp en serie kameraer langs et spor og tok bilder i rask rekkefølge som en hest sprang forbi. Denne prosessen tillot ham å fange 16 bilder av hestens løp. I et av bildene hadde hesten faktisk alle fire benene fra bakken.


Muybridge's "The Horse in Motion" -fotoene med det første bildet fjernet.

Muybridge gjentok senere eksperimentet og plasserte hvert bilde på en enhet som kunne projisere bildene i rask rekkefølge for å gi illusjonen av hesten løpende, og skape den første filmprojektoren.

Prosessen med å endre bilder i rask rekkefølge for å gi illusjonen av bevegelsen kalles animasjon.


Sprite

En sprite er et enkelt grafisk bilde som er innarbeidet i en større scene slik at den ser ut til å være en del av scenen.

Sprites er en populær måte å skape store, komplekse scener som du kan manipulere hver sprite separat fra resten av scenen. Dette gir større kontroll over hvordan scenen blir gjengitt, samt over hvordan spillerne kan samhandle med scenen.

Det er ikke uvanlig at spill har tiere til hundrevis av sprites. Hvis du legger til hver av disse som et enkeltbilde, vil det bli mye minne og prosessorkraft. For å hjelpe til med å håndtere sprites og unngå å bruke så mange bilder, bruker mange spill spritesheets.

Hvis du leter etter forhåndsgjorte, kreative grafikk, kan du oppdage Sprites og Ark som kanskje bare passer perfekt for dine behov. Eller du kan bestille ditt eget tilpassede spillkarakter på Envato Studio.


Spritesheet

Når du setter mange sprites inn i et enkelt bilde, får du et spritesheet.

Spritesheets brukes til å fremskynde prosessen med å vise bilder på skjermen; Det er mye raskere å hente ett bilde og bare vise en del av bildet enn det er å hente mange bilder og vise dem.

Spritesheet animasjon er ikke noe annet enn å ta et spritesheet og endre hvilken sprite gjengis i rask rekkefølge for å gi illusjonen av bevegelse, akkurat som en filmprojektor som viser en film.


Deler av et Spritesheet

Spritesheets består av to deler: rammer og sykler

En ramme er et enkelt bilde (eller sprite) fra spritesheet. Når man går tilbake til Muybridges hesteksempel, vil hvert bilde av hesten i bildet være en ramme.

Når rammene legges i en ordre som skaper en kontinuerlig bevegelse, oppretter det en syklus.

Å sette fotografiene av hesten i den rekkefølgen de ble tatt, gir en "run" syklus siden hesten løper (i motsetning til en "tur" eller "tomgang" syklus).


Koding Spritesheet Animasjoner

Det er tre deler for å kode et spritesheet-animasjon:

  1. Opprette bildet
  2. Oppdaterer bildet til hver ramme av animasjonen
  3. Tegner rammen til skjermen

Opprette bildet

Vi starter med å opprette funksjonen (eller klassen) som skal håndtere vår spritesheet-animasjon. Denne funksjonen vil skape bildet og sette banen slik at vi kan bruke den til å tegne.

funksjon SpriteSheet (sti, frameWidth, frameHeight) var image = new Image (); var rammerPerRow; // beregne antall bilder på rad etter at bildet laster var selv = dette; image.onload = function () framesPerRow = Math.floor (image.width / frameWidth); ; image.src = path; 

Siden ulike spritesheets kan ha forskjellige rammestørrelser, må vi passere rammebredden og høyden slik at vi kan nøyaktig beregne hvor mange rammer som er på rad og kolonne på bildet. Vi bruker denne informasjonen senere for å tegne animasjonen til skjermen.

Det er viktig at hver ramme av spritesheet er den samme bredden og høyden; Ellers er det veldig vanskelig å tegne animasjonen til skjermen.

Oppdaterer bildet

For å oppdatere spritesheet-animasjonen, er alt vi trenger å endre, hvilken ramme vi vil tegne. Nedenfor er spritesheet delt inn i hver av sine rammer og nummerert.

Ved hver ramme av spillet oppdaterer vi spritesheet. Vi vil imidlertid ikke at animasjonen skal bytte til neste ramme hver ramme, så vi må fortelle vårt spritesheet hvor mange rammer som skal vente før overgang.

Det er viktig å merke seg at ikke hvert spritesheet har en sprite i hver ledig ramme (for eksempel bildet av Muybridge's "The Horse in Motion"). Hvis vi skulle prøve å animere vår spritesheet med en tom ramme, ville det være et blip i animasjonen hver gang den tomme rammen er tegnet til skjermen.

For å kompensere for dette, vil vi også fortelle spritesheet hva det siste rammenummeret er, slik at vi ikke animerer tomme rammer.

funksjon SpriteSheet (sti, frameWidth, frameHeight, frameSpeed, endFrame) // kode fjernet for korthet var currentFrame = 0; // gjeldende ramme for å tegne var counter = 0; // holde orden på bildefrekvensen // Oppdater animasjonen this.update = function () // oppdatering til neste ramme hvis det er tid hvis (counter == (frameSpeed ​​- 1)) currentFrame = (currentFrame + 1)% endFrame; // oppdater counter counter = (counter + 1)% frameSpeed; ;

Ved å bruke modulo-operatøren (%) for currentFrame, Vi kan lage en kontinuerlig sløyfe hver gang endFrame er nådd, den currentFrame vil gå tilbake til 0, dermed looping animasjonen.

Moduloperatøren for telleren forhindrer heltall overløp.

Tegne bildet

Tegne et bilde fra et spritesheet fungerer på samme måte som å tegne et bilde fra et flisekart.

Vi beregner raden på bildet vi vil tegne ved å ta modulo av gjeldende ramme og antall bilder per rad. Vi beregner kolonnen ved å dividere gjeldende ramme med antall rammer per rad.

Ved hjelp av denne raden og kolonnen kan vi deretter beregne koordinatene til rammen for å tegne ved å multiplisere dem med frameWidth og frameHeight, henholdsvis:

 // Tegn nåværende ramme this.draw = function (x, y) // få rad og kol av rammen var row = Math.floor (currentFrame / framesPerRow); var col = Math.floor (currentFrame% framesPerRow); ctx.drawImage (bilde, col * frameWidth, rad * frameHeight, frameWidth, frameHeight, x, y, frameWidth, frameHeight); ; 

Med spritesheet-funksjonen på plass, kan vi nå bruke den til å lage en spritesheet-animasjon:

spritesheet = nytt SpriteSheet ('Walk_Cycle_Image.png', 125, 125, 3, 16); funksjon animere () requestAnimFrame (animere); ctx.clearRect (0, 0, 150, 150); spritesheet.update (); spritesheet.draw (12,5, 12,5); 


Flere sykluser i ett spretterblad

Ovennevnte kode vil fungere for et spritesheet som inneholder en syklus. Det er imidlertid ikke uvanlig at et spritesheet holder flere sykluser, noe som betyr at det vil være flere animasjoner i et enkelt spritesheet.

Vi må endre hvordan vårt spritesheet fungerer for å håndtere flere animasjoner fra et enkelt spritesheet.

Opprette bildet

Siden bildet forblir det samme mellom animasjoner, deler vi vårt spritesheet i to funksjoner: ett for bildet og ett for hver animasjon fra spritesheet.

Et spritesheet vil holde informasjonen om bildet og rammestørrelsene.

funksjon SpriteSheet (sti, frameWidth, frameHeight) this.image = nytt bilde (); this.frameWidth = frameWidth; this.frameHeight = frameHeight; // beregne antall bilder på rad etter at bildet laster var selv = dette; this.image.onload = function () self.framesPerRow = Math.floor (self.image.width / self.frameWidth); ; this.image.src = path; 

Oppdaterer og tegner bildet

En animasjon vil være ansvarlig for å oppdatere og tegne spritesheet.

funksjon Animasjon (spritesheet, frameSpeed, startFrame, endFrame) var animationSequence = []; // array som holder orden på animasjonen var currentFrame = 0; // gjeldende ramme for å tegne var counter = 0; // holde orden på bildefrekvensen // lage sekvensen av rammenumre for animasjonen for (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); 

Siden spritesheet inneholder flere rammer enn noen enkelt animasjon trenger, må vi vite hvilket rammenummer som skal startes og avslutte animasjonen. Ved å bruke denne informasjonen oppretter vi en rekke rammenumre slik vi kan bruke currentFrame for å få tilgang til det riktige rammenummeret.


Setter Spritesheet til bruk

Med animasjonen klar til å håndtere et spritesheet, kan vi bruke det til å lage en enkel, uendelig runner i Canabalt-stilen:


Truffet Rom å hoppe.

Du kan finne full kildekoden for dette i vår GitHub repo. Hva er din høy poengsum?

Ekstra ressurser

Hvis du er på utkikk etter kreativ spillgrafikk, har vi rimelige Game Sprites and Sheets på GraphicRiver, som kanskje bare er løsningen ditt spill trenger. Eller hvis du er interessert i å få litt hjelp med animasjonene dine, har Envato Studio en flott samling av animatorer som du kanskje vil utforske.