Spritesheets worden al heel lang in spellen gebruikt. Klassieke games zoals Legend of Zelda: A Link to the Past en zelfs moderne games zoals Cut the Rope hebben ze gebruikt. In dit artikel zullen we praten over wat spritesheet-animatie is en hoe je dit kunt coderen, en we zullen ook laten zien hoe ze in een klein spel kunnen worden gebruikt. Ik zal JavaScript gebruiken voor de code, maar je zou in elke taal moeten kunnen volgen.
gerelateerde berichtenDeze tutorial maakt deel uit van een speciale samenwerking tussen een artiest, een animator en een gamedev!
Voordat we kunnen beginnen met praten over het coderen van een sprite-animatie, moeten we eerst een paar termen definiëren: animatie, sprite, en spritesheet.
gerelateerde berichtenAanvullende bronnen die u mogelijk handig vindt:
Einde in 1872 kreeg Eadweard Muybridge de opdracht om te bewijzen of een paard alle vier de benen van de grond optilde toen het rende. Om dit te doen, zette hij een reeks camera's langs een parcours op en maakte hij foto's snel achter elkaar als een paard voorbij liep. Dit proces stelde hem in staat om 16 foto's te maken van de run van het paard. Op een van de foto's had het paard inderdaad alle vier de benen van de grond.
Muybridge herhaalde later het experiment en plaatste elke foto op een apparaat dat de foto's snel achter elkaar kon projecteren om de illusie te geven dat het paard liep, waardoor de eerste filmprojector ontstond.
Het proces van snel achter elkaar schakelen van afbeeldingen om de illusie van beweging te geven, wordt animatie genoemd.
Een sprite is een enkele grafische afbeelding die is opgenomen in een grotere scène zodat deze deel lijkt uit te maken van de scène.
Sprites zijn een populaire manier om grote, complexe scènes te maken, omdat je elke sprite apart van de rest van de scène kunt manipuleren. Dit geeft meer controle over hoe de scène wordt weergegeven, en over hoe de spelers kunnen communiceren met de scène.
Het is niet ongebruikelijk dat games tientallen tot honderden sprites hebben. Het laden van elk van deze als een individuele afbeelding kost veel geheugen en verwerkingskracht. Om sprites te beheren en het gebruik van zoveel afbeeldingen te voorkomen, gebruiken veel games spritesheets.
Als u op zoek bent naar vooraf gemaakte, creatieve afbeeldingen, ontdek dan Game Sprites en Spreadsheets die misschien precies geschikt zijn voor uw behoeften. Of u kunt uw eigen aangepaste sprite voor sprite op Envato Studio bestellen.
Wanneer u veel sprites in een enkele afbeelding plaatst, krijgt u een spritesheet.
Spritesheets worden gebruikt om het proces van het weergeven van afbeeldingen naar het scherm te versnellen; Het is veel sneller om één afbeelding op te halen en slechts een deel van die afbeelding weer te geven dan om veel afbeeldingen op te halen en weer te geven.
Spritesheet-animatie is niets anders dan een spritesheet maken en wijzigen welke sprite snel achter elkaar wordt weergegeven om de illusie van beweging te geven, net als een filmprojector die een film laat zien.
Spritesheets bestaan uit twee delen: frames en cycli
Een frame is een enkele afbeelding (of sprite) van het sprite-blad. Teruggaand naar het voorbeeld van het paard van Muybridge, zou elke afbeelding van het paard in de afbeelding een kader zijn.
Wanneer de frames in een volgorde worden geplaatst die zorgt voor een continue beweging, wordt een cyclus gemaakt.
De foto's van het paard plaatsen in de volgorde waarin ze zijn genomen, produceert een "run" -cyclus sinds het paard loopt (in tegenstelling tot een "loop" of "inactieve" cyclus).
Er zijn drie onderdelen voor het coderen van een spritesheet-animatie:
We beginnen met het maken van de functie (of klasse) die onze spritesheet-animatie verwerkt. Deze functie maakt de afbeelding en stelt zijn pad in zodat we deze kunnen gebruiken om te tekenen.
functie SpriteSheet (pad, frameWidth, frameHeight) var image = new Image (); var framesPerRow; // bereken het aantal frames in een rij nadat de afbeelding var self = this is geladen; image.onload = function () framesPerRow = Math.floor (image.width / frameWidth); ; image.src = pad;
Omdat verschillende spritesheets verschillende framegroottes kunnen hebben, moeten we de framebreedte en -hoogte doorgeven, zodat we nauwkeurig kunnen berekenen hoeveel frames zich in een rij en kolom van de afbeelding bevinden. We gebruiken deze informatie later om de animatie naar het scherm te tekenen.
Het is belangrijk dat elk frame van het sprite-blad dezelfde breedte en hoogte heeft; anders is het erg moeilijk om de animatie op het scherm te tekenen.Om de spritesheetanimatie bij te werken, hoeven we alleen maar te veranderen welk frame we zullen tekenen. Hieronder is het spritesheet opgedeeld in elk van de frames en genummerd.
In elk frame van het spel werken we het spritesheet bij. We willen echter niet dat de animatie elk frame naar het volgende frame overschakelt, dus moeten we ons spritesheet vertellen hoeveel frames moeten wachten voordat het wordt overgezet.
Het is belangrijk op te merken dat niet elke spritesheet een sprite heeft in elk beschikbaar frame (zoals de afbeelding van "The Horse in Motion" van Muybridge). Als we zouden proberen om onze spritesheet met een leeg frame te animeren, zou er een blip in de animatie zijn telkens wanneer het lege frame naar het scherm wordt getrokken.
Om dit te compenseren, vertellen we ook het sprite-blad wat het laatste framenummer is, zodat we geen lege frames animeren.
functie SpriteSheet (pad, frameWidth, frameHeight, frameSpeed, endFrame) // code verwijderd voor beknoptheid var currentFrame = 0; // het huidige frame om var-teller te tekenen = 0; // houd de framesnelheid bij // Update de animatie this.update = function () // update naar het volgende frame als het tijd is if (counter == (frameSpeed - 1)) currentFrame = (currentFrame + 1)% Zijdeel; // update de counter counter = (counter + 1)% frameSpeed; ;
Door de modulo-operator te gebruiken (%
) voor de currentFrame
, we kunnen een continue lus maken-telkens het Zijdeel
is bereikt, de currentFrame
zal terugkeren naar 0
, dus looping van de animatie.
De modulo-operator voor de teller voorkomt integer-overloop.
Het tekenen van een afbeelding uit een spritesheet werkt op precies dezelfde manier als het tekenen van een afbeelding uit een tegelkaart.
We berekenen de rij van de afbeelding die we willen tekenen door de modulo van het huidige frame en het aantal frames per rij te nemen. We berekenen de kolom door het huidige frame te delen door het aantal frames per rij.
Met behulp van deze rij en kolom kunnen we vervolgens de coördinaten van het frame berekenen door te vermenigvuldigen met steigerbreedte
en frameHeight
, respectievelijk:
// Teken het huidige frame this.draw = function (x, y) // haal de rij en kolom van het frame var row = Math.floor (currentFrame / framesPerRow); var col = Math.floor (currentFrame% framesPerRow); ctx.drawImage (afbeelding, col * frameWidth, row * frameHeight, frameWidth, frameHeight, x, y, frameWidth, frameHeight); ;
Met de sprite-functie op zijn plaats, kunnen we het nu gebruiken om een spritesheet-animatie te maken:
spritesheet = nieuwe SpriteSheet ('Walk_Cycle_Image.png', 125, 125, 3, 16); function animeren () requestAnimFrame (animeren); ctx.clearRect (0, 0, 150, 150); spritesheet.update (); spritesheet.draw (12.5, 12.5);
De bovenstaande code werkt voor elk spritesheet dat één cyclus bevat. Het is echter niet ongebruikelijk dat een spritesheet meerdere cycli bevat, wat betekent dat er meerdere animaties in één spritesheet zullen zijn.
We zullen moeten veranderen hoe onze spritesheet werkt om meerdere animaties van een enkel spritesheet af te handelen.
Omdat het beeld tussen animaties hetzelfde blijft, zullen we ons sprite-blad in twee functies verdelen: één voor de afbeelding en één voor elke animatie van het sprite-blad.
Een spritesheet bevat informatie over de afbeelding en de framegroottes.
functie SpriteSheet (pad, frameWidth, frameHeight) this.image = new Image (); this.frameWidth = frameWidth; this.frameHeight = frameHeight; // bereken het aantal frames in een rij nadat de afbeelding var self = this is geladen; this.image.onload = function () self.framesPerRow = Math.floor (self.image.width / self.frameWidth); ; this.image.src = pad;
Een animatie zorgt voor het updaten en tekenen van het spritesheet.
functie Animatie (spritesheet, frameSpeed, startFrame, endFrame) var animationSequence = []; // array met de volgorde van de animatie var currentFrame = 0; // het huidige frame om var-teller te tekenen = 0; // houd de framesnelheid bij / maak de reeks framenummers voor de animatie voor (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);
Omdat de spritesheet meer frames bevat dan welke enkele animatie dan ook nodig heeft, moeten we weten welk framenummer de animatie moet starten en eindigen. Met behulp van deze informatie maken we een reeks framenummers zodat we deze kunnen gebruiken currentFrame
om toegang te krijgen tot het juiste framenummer.
Met de animatie klaar om elk spritesheet te verwerken, kunnen we het gebruiken om een eenvoudige Canabalt-stijl oneindige runner te maken:
Je vindt de volledige broncode hiervoor in onze GitHub-repo. Wat is je hoogste score?
Als u op zoek bent naar creatieve game-graphics, hebben we betaalbare gamespreads en -spreadsheets op GraphicRiver, misschien wel de oplossing die uw game nodig heeft. Of, als je geïnteresseerd bent in hulp bij je animaties, heeft Envato Studio een geweldige verzameling animators die je misschien leuk vindt om te verkennen.