Ștampilele de scris au fost folosite în jocuri mult timp. Jocurile clasice, cum ar fi Legenda lui Zelda: O legătură cu trecutul și chiar jocuri moderne, cum ar fi Cut the the Rope, le-au folosit. În acest articol, vom vorbi despre animația spritesheet și cum să codificăm aceasta și vom demonstra, de asemenea, modul în care acestea pot fi folosite într-un joc mic. Voi folosi JavaScript pentru cod, dar ar trebui să puteți urmări în orice limbă.
postări asemănatoareAcest tutorial face parte dintr-o colaborare specială între un artist, un animator și un gamedev!
Înainte de a începe să vorbim despre cum să codificăm o animație spritesheet, ar trebui să definim mai întâi câțiva termeni: animaţie, spiriduș, și spritesheet.
postări asemănatoareResurse suplimentare vă pot fi utile:
Înapoi în 1872, Eadweard Muybridge a fost însărcinat să demonstreze dacă un cal a ridicat toate cele patru picioare de pe sol imediat când a fugit. Pentru a face acest lucru, a stabilit o serie de camere de luat vederi de-a lungul unei piste și a fotografiat în succesiune rapidă pe măsură ce un cal a alergat. Acest proces ia permis să captureze 16 imagini ale alergării calului. Într-una din imagini, calul are într-adevăr toate cele patru picioare de pe pământ.
Muybridge a repetat mai târziu experimentul și a plasat fiecare fotografie pe un dispozitiv care ar putea proiecta fotografiile în succesiune rapidă pentru a da iluzia calului de a alerga, creând primul proiector de film.
Procesul de schimbare a imaginilor în succesiune rapidă pentru a da iluzia mișcării se numește animație.
Un sprite este o singură imagine grafică care este încorporată într-o scenă mai mare, astfel încât pare să fie parte a scenei.
Spritele sunt o modalitate populară de a crea scene mari, complexe, deoarece puteți manipula fiecare sprite separat de restul scenei. Acest lucru permite un control mai bun asupra modului în care este oferită scena, precum și asupra modului în care jucătorii pot interacționa cu scena.
Nu este neobișnuit ca jocurile să aibă zeci și sute de sprites. Încărcarea fiecăruia dintre acestea ca o imagine individuală ar consuma multă memorie și putere de procesare. Pentru a vă ajuta să gestionați spritele și pentru a evita utilizarea atât de multe imagini, multe jocuri folosesc sprite.
Dacă sunteți în căutarea de grafică creativă pre-făcută, descoperiți jocurile Sprite și foi care pot fi potrivite pentru nevoile dvs. Sau puteți să comandați propriul dvs. personalizat personaj de joc pe Envato Studio.
Când puneți mai multe sprite într-o singură imagine, obțineți o foaie de sprite.
Spreisteheets sunt folosite pentru a accelera procesul de afișare a imaginilor pe ecran; Este mult mai rapid să preluați o imagine și să afișați doar o parte din acea imagine decât să preluați multe imagini și să le afișați.
Spritesheet animația nu este altceva decât a lua o spritesheet și schimbarea care sprite este redat în succesiune rapidă pentru a da iluzia de mișcare, la fel ca un proiector de film care afișează un film.
Spreisteheets sunt alcătuite din două părți: cadre și cicluri
Un cadru este o singură imagine (sau sprite) din foaia de spirite. Revenind la exemplul calului lui Muybridge, fiecare imagine a calului din imagine ar fi un cadru.
Când cadrele sunt plasate într-o ordine care creează o mișcare continuă, creează un ciclu.
Punerea fotografiilor calului în ordinea în care au fost luate produce un ciclu de "alergare" de când calul se execută (spre deosebire de un ciclu de "mers pe jos" sau "inactiv").
Există trei părți pentru a codifica o animație spritesheet:
Vom începe prin crearea funcției (sau a clasei) care se va ocupa de animația noastră spritesheet. Această funcție va crea imaginea și va stabili cărarea acesteia, astfel încât să o putem folosi pentru a desena.
funcția SpriteSheet (cale, cadruWidth, frameHeight) var image = new Image (); var framesPerRow; // calcula numărul de cadre într-un rând după încărcarea imaginii var self = aceasta; image.onload = funcție () framesPerRow = Math.floor (imagine.width / frameWidth); ; image.src = calea;
Deoarece foile de sprite diferite pot avea diferite dimensiuni ale cadrelor, va trebui să trecem la lățimea și înălțimea cadrului astfel încât să putem calcula cu exactitate câte cadre sunt într-un rând și într-o coloană a imaginii. Vom folosi aceste informații mai târziu pentru a desena animația pe ecran.
Este important ca fiecare cadru al sprite să aibă aceeași lățime și înălțime; altfel, desenarea animației pe ecran este foarte dificilă.Pentru a actualiza animația spritesheet, tot ce trebuie să facem este să schimbăm cadrul pe care îl vom desena. Mai jos este foaia de sprite împărțită în fiecare dintre cadrele sale și numerotată.
În fiecare cadru al jocului, vom actualiza foaia de înfruntat. Cu toate acestea, nu vrem ca animația să treacă la următorul cadru în fiecare cadru, așa că trebuie să ne spună foaia de înmatriculare câte cadre să aștepte înainte de a trece.
Este important să rețineți că nu fiecare foaie de sprite are un sprite în fiecare cadru disponibil (cum ar fi imaginea lui Muybridge "The Horse in Motion"). Dacă încercăm să animăm foaia de sprite cu un cadru gol, ar fi o clipită în animație de fiecare dată când cadrul gol este desenat pe ecran.
Pentru a compensa acest lucru, vom spune, de asemenea, la spritesheet ceea ce este ultimul număr al cadrului, astfel încât să nu animăm cadrele goale.
funcția SpriteSheet (cale, frameWidth, frameHeight, frameSpeed, endFrame) // codul eliminat pentru brevity var currentFrame = 0; // cadrul curent pentru a extrage var counter = 0; // urmăriți rata cadrelor // actualizați animația this.update = function () // actualizați la următorul cadru dacă este timpul dacă (counter == (frameSpeed - 1)) currentFrame = (currentFrame + 1)% endFrame; // actualizați contorul de counter = (contra + 1)% frameSpeed; ;
Prin utilizarea operatorului modulo (%
) pentru currentFrame
, putem crea o buclă continuă - de fiecare dată endFrame
este atins, currentFrame
va reveni la 0
, lăsând astfel animația.
Operatorul modulo pentru contor previne depășirea întregului număr.
Desenarea unei imagini dintr-o foaie de sprite funcționează exact în același mod ca și desenarea unei imagini dintr-o hartă de țigle.
Calculăm rândul imaginii pe care dorim să o desenectăm luând modulul cadrului curent și numărul de cadre pe rând. Calculăm coloana împărțind cadrul curent cu numărul de cadre pe rând.
Folosind acest rând și coloană, putem calcula apoi coordonatele cadrului care trebuie desenate prin înmulțirea lor cu frameWidth
și frameHeight
, respectiv:
// Desenați cadrul curent this.draw = funcție (x, y) // obțineți rândul și colul cadrului var row = Math.floor (currentFrame / framesPerRow); var col = Math.floor (actualFrame% framesPerRow); ctx.drawImage (imagine, col * cadru Lățime, rând * CadruValoare, Lățime cadru, CadruHeight, x, y, cadru Lățime, cadruValoare); ;
Cu ajutorul funcției sprite, putem folosi acum pentru a crea o animație spritesheet:
spritesheet = noua SpriteSheet ('Walk_Cycle_Image.png', 125, 125, 3, 16); funcția animate () requestAnimFrame (animat); ctx.clearRect (0, 0, 150, 150); spritesheet.update (); spritesheet.draw (12,5, 12,5);
Codul de mai sus va funcționa pentru orice foaie de sprite care conține un singur ciclu. Cu toate acestea, nu este neobișnuit ca o foaie de date să țină mai multe cicluri, ceea ce înseamnă că vor exista mai multe animații într-o singură foaie de spririte.
Va trebui să schimbăm modul în care funcționează fișierul nostru spritesc pentru a gestiona mai multe animații dintr-o singură foaie de date.
Din moment ce imaginea rămâne aceeași între animații, vom împărți foaia noastră de sprite în două funcții: una pentru imagine și una pentru fiecare animație din fișierul spritesheet.
O foaie de sinteză va conține informațiile despre imagine și dimensiunile cadrelor.
funcția SpriteSheet (cale, cadruWidth, frameHeight) this.image = imagine nouă (); this.frameWidth = frameWidth; this.frameHeight = frameHeight; // calcula numărul de cadre într-un rând după încărcarea imaginii var self = aceasta; this.image.onload = funcție () self.framesPerRow = Math.floor (auto.image.width / self.frameWidth); ; this.image.src = calea;
O animație va fi responsabilă de actualizarea și desenarea foii de sprite.
funcția Animație (spritesheet, frameSpeed, startFrame, endFrame) var animationSequence = []; // array care deține ordinea animației var currentFrame = 0; // cadrul curent pentru a extrage var counter = 0; // urmăriți rata de cadre // creați secvența numerelor de cadre pentru animația pentru (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);
Întrucât foaia de spririte conține mai multe cadre decât va fi nevoie de o singură animație, va trebui să știm ce număr de cadru să pornească și să se termine animația. Folosind aceste informații, vom crea o serie de numere de cadre pentru a le putea folosi currentFrame
pentru a accesa numărul corect al cadrului.
Cu animația pregătită pentru a manipula orice foaie sprite, o putem folosi pentru a face un simplu alergator infinit în stilul Canabalt:
Puteți găsi codul sursă complet pentru acest lucru în replica noastră GitHub. Care este scorul tău mare??
Dacă sunteți în căutarea de grafică de joc creativ, avem Sprites și Foi de joc la prețuri accesibile pe GraphicRiver, care poate fi doar soluția pe care jocul dvs. are nevoie. Sau, dacă sunteți interesat să obțineți ajutor cu animațiile dvs., Envato Studio are o mare colecție de animatori pe care ați putea dori să o explorați.