Dus je hebt je geweldige game in de maak, het heeft allerlei complexe fysica, epische vijandelijke AI of wat-heb-jij ook. Maar het voelt levenloos. Je wilt wat OOMPH, je wilt wat animatie!
Als je gaat opzoeken hoe je kunt animeren, is het eerste antwoord dat je tegenkomt waarschijnlijk een methode die spritesheets en blitting gebruikt. Sterker nog, bijna alle tutorials op het web praten over niets maar bleken, alsof er geen andere manier is om te animeren. Maar in mijn ervaring is er een betere manier om je orcs en goblins te animeren!
Deze methode kan worden aangeroepen animeren met asset-sheets - of meer technisch, tweening met asset-sheets - in tegenstelling tot gebruik sprite-vellen. Voordat we ingaan op precies wat dit betekent, laten we een belangrijke vraag overwegen:
Hieronder staan enkele redenen waarom je zou in bepaalde gevallen geen blitting willen gebruiken.
Of we het nu hebben over RAM of schijfruimte, Sprite-sheets kunnen gemakkelijk dingen verstoppen. Vooral als je HD-afbeeldingen probeert te maken. Grote sprite-sheets moeten mogelijk in meerdere PNG's worden opgesplitst, kostbare RAM opnemen en de omvang van je spel omhoog schieten als je niet oppast.
Wat gebeurt er als je een animatie wilt versnellen? U kunt sommige frames overslaan, maar hoe zit het met vertragen? De animatie zou schokkerig en lelijk lijken. Zelfs als je alleen 60 fps wilt ondersteunen, wat als een computer het spel sneller kan uitvoeren? Je zou kunnen beschikken over verbluffend soepele animaties met hogere framesnelheden zonder extra werk, en het zou ook goed zijn als je ervoor kiest om de framesnelheid van het spel op elk gewenst moment te wijzigen.
En wat als je wilde dat er iets zou gebeuren als de armen van de speler ergens kwamen? Of om hem iets te laten ophalen? U moet zijn arm tijdens de animatie handmatig markeren, wat tijdrovend kan zijn omdat u geen gegevens kunt krijgen over waar een van zijn ledematen van een sprite-blad zijn.
Wat gebeurt er als de speler rent en plotseling springt? Het snijdt meteen de spronganimatie. Dit ziet er schokkerig uit, en dit zou gebeuren telkens wanneer de animatie naar een nieuwe staat overgaat. Je zou een overgang moeten maken voor elk paar animaties die je hebt, wat niet alleen waanzinnig tijdrovend is, maar ook het nadelige effect heeft van het verhogen van je RAM-gebruik zoals eerder besproken.
Met behulp van asset-sheets kunnen niet alleen de animaties dynamisch zijn en opgeschaald worden met een FPS, maar ook soepel tussen twee willekeurige toestanden overgaan, maar ook neemt een minieme hoeveelheid schijfruimte en RAM in vergelijking met blitting!
Dit is niet eens erg nieuw. Sommige populaire spellen gebruiken het, zoals de onlangs populaire afsluiting. De enige beperking is dat het geen frame-by-frame (FBF) animatie kan doen, omdat het afhankelijk is van tweening - dus als je complexe explosies hebt, moet je spritebladen gebruiken.
Maar in veel gevallen zul je merken dat dit niet nodig is, en het is meer dan de moeite waard om een systeem als dit voor je spel te hebben, omdat sommige spellen volledig op dit kunnen vertrouwen, waardoor een hoop overhead wordt afgeschud . Het is ook echt cool omdat het lijkt op hoe je een 3D-game zou kunnen animeren!
Dus om samen te vatten:
Dit is een personage en zijn eigendommenblad.
Zoals de naam al aangeeft, is een activablad een PNG met alle ledematen / items van het teken of object gescheiden.
En hier zijn de animatiegegevens in JSON (u kunt natuurlijk het formaat gebruiken waarmee u het liefst werkt):
// dit fragment toont de eerste drie frames van de "Body" -animatie "-name": "Body", "Frame": ["-x": "0.65", "-y": "- 64.45", " -rotatie ":" 0.000 ", " -x ":" 2.45 "," -y ":" - 64.45 "," -rotation ":" 0.279 "," -x ":" 3.30 "," - y ":" - 64.05 "," -rotation ":" 0.707 "
Nu deze twee samen gecombineerd worden in een geweldige motor, krijg je:
En in tegenstelling tot een gebloeide animatie, zou dit kunnen versnellen of zeer soepel verlopen. Dus dit is wat we gaan doen.
De eerste stap is om uw activablad gereed te maken. U kunt dit op verschillende manieren doen. Het punt is om te eindigen met een blad met de activa en een gegevensbestand met de posities van de activa in het blad. Dit is exact dezelfde methode als voor het maken van een sprite-sheet, behalve dat in plaats van sprites u afzonderlijke items toevoegt.
Exporteer de ledematen en stukken van je speler als individuele PNG's en gebruik vervolgens een programma zoals Texture Packer om ze in een blad te groeperen. Er zijn andere programma's, maar ik geef persoonlijk de voorkeur aan Texture Packer vanwege de veelzijdigheid en veelzijdigheid ervan.
Tip: Welke software u ook gebruikt om uw vellen te maken, zorg ervoor dat er ten minste 2 px opvulling is tussen elk item en 1px-extrusie. Dit zal in de toekomst enkele vervelende problemen voorkomen.Dit is misschien wel de belangrijkste stap, want dit zijn de gegevens die u gebruikt om alle animaties tijdens runtime te maken. Het is ook belangrijk omdat het platformonafhankelijk is. Je kunt dezelfde animatiegegevens op een PS3 gebruiken als op een iPhone.
De gegevens die u nodig hebt, zijn de x-positie, y-positie, rotatiewaarde en andere dergelijke eigenschappen van elk item voor elk frame van uw animatie.
Als u Adobe Flash gebruikt om te animeren, kunt u eenvoudig uw animatiegegevens exporteren. In theorie hoef je alleen maar door de kinderen van MovieClip te bladeren en door de frames te stappen terwijl je de gegevens ophaalt.
Dit kan echter vervelend zijn. Gelukkig zijn er hulpmiddelen die dit al doen. Grapefrukt is bijvoorbeeld een geweldige tool met een verscheidenheid aan functies, waaronder het exporteren van spritesheets en animatiegegevens in XML.
Notitie: U moet ervoor zorgen dat de namen van uw activa in de gegevens overeenkomen met de namen op het activablad, zodat ze gemakkelijk kunnen worden gekoppeld.Als u het wilt wijzigen of als u alleen de functie voor het exporteren van animatie wilt, kunt u ervoor kiezen mijn eigen klasse voor het exporteren van animaties te gebruiken, die automatisch animatiegegevens in een JSON-bestand in dezelfde map exporteert. Je kunt het hier downloaden, samen met een voorbeeldblad met items en een voorbeeldanimatie.
Als u andere animatiesoftware (of uw eigen) gebruikt, zou het niet te moeilijk moeten zijn om een plug-in te vinden of te schrijven die de coördinaten en gegevens van de activa bij elk frame exporteert.
Hier is een lijst met alle kenmerken die de Flash-exporteurs voor elk item uitvoeren:
X
en Y
omwenteling
(in graden of radialen)scaleX
en scaleY
(hoeveel het activum wordt geschaald op elke as)alpha
(transparantie)ColorMatrix
(hiermee kunt u gegevens exporteren, zoals helderheid, tint en contrast)Er is geen limiet voor de hoeveelheid gegevens die u kunt uitvoeren. Ik heb bijvoorbeeld een extra toegevoegd diepte
veld in mijn exporteur die me de diepgang van elk item vertelt. Zodat als de animator de items in een bepaalde volgorde rangschikt of de lagen wijzigt, deze automatisch worden bijgewerkt in de engine.
Zoals u kunt zien, kunt u veel verschillende soorten animatie en functies met de juiste gegevens doen.
U hebt nu dus uw inventaris, het bijbehorende gegevensbestand en de JSON-animatie gereed. Vervolgens komt het harde gedeelte: het schrijven van het animatiesysteem dat onze gegevens begrijpt en de afzonderlijke activa en onbewerkte gegevens omzet in prachtige animaties.
De eerste stap is om de animatiegegevens te laden. Dit zou gemakkelijk moeten zijn, aangezien de meeste talen een JSON- of XML-parser hebben.
Vervolgens splits je elk activum uit het blad (of liever, render alleen de rechthoek met je item) en sla ze op in een array.
Dus onze game-objecten hebben nu twee arrays: een assetArray
die de werkelijke bezittingen heeft, en een animationArray
welke de animatiegegevens heeft.
animationArray
en geef de namen van de activa. Dit is zodat u eenvoudig toegang hebt tot de juiste gegevens uit de animatiereeks, dus als ik de waarde afdruk van object.assetArray [5] .name
, Ik zou bijvoorbeeld "been" krijgen. Dan als ik ga en toegang object.animationArray [ "leg"]
, Ik zou de animatiegegevens voor de poot van het personage moeten krijgen. Laten we nu een code bekijken!
/// In de updatefunctie van het object var animationArray: Array = object.animationArray; var assetArray: Array = object.assetArray; // we doorlopen alle activa voor (var i: int = 0; i < assetArray.length; i++) assetArray[i].x = object.x; assetArray[i].y = object.y; assetArray[i].angle = object.angle;
Tot nu toe doorlopen we alle activa om hun in te stellen X
, Y
en omwenteling
naar dat van het moederobject. Dit is belangrijk, zodat u uw objecten kunt laten bewegen zonder de animatie te verpesten, zodat de animatiecoördinaten relatief zijn ten opzichte van dat punt.
/// In de updatefunctie van het object var animationArray: Array = object.animationArray; var assetArray: Array = object.assetArray; // we doorlopen alle activa voor (var i: int = 0; iHier hebben we de regel toegevoegd
+ animationArray [assetArray [i] .name] [currentFrame] .x
, waarcurrentFrame
is een geheel getal dat het huidige frame vertegenwoordigt waarin u zich bevindt.Nu zouden alle activa zich in hun eerste frameposities bevinden, dus als u eenmaal bent gestegen
currentFrame
, ze zouden op de posities van Frame 2 staan, enzovoort.Gefeliciteerd, je hebt animatie gemaakt! Het ziet er hetzelfde uit als als je het had gedaan met een spritesheet, behalve dat het je maar een paar kilobytes kostte in plaats van megabytes.
Dit is slechts een heel eenvoudig voorbeeld. Normaal gesproken wilt u aparte animaties hebben, zoals een "lopende" animatie met 30 frames en een "jump" -animatie met 12 frames. Om dit te doen, voegt u gewoon een andere laag toe aan uw animatiearrayhiërarchie zodat het er ongeveer zo uitziet:
Stap 4: Interpolatie
We hoeven daar niet te stoppen. We willen proberen onze animaties zo soepel en dynamisch mogelijk te maken zoals beloofd.
Normaal gesproken zou dit iets tamelijk moeilijk zijn - we zouden de volledige staat van het vorige frame moeten opslaan om te interpoleren naar de stroom. Maar gelukkig slaat ons systeem die informatie al op!
U altijd weet waar het vorige frame was en waar het volgende frame zal zijn, dus interpolatie tussen frames is zo simpel als dit:
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 + XHier krijgen we het verschil tussen het volgende frame en het huidige frame, vermenigvuldigd met a
TimeFactor
welke is de tijd tussen de twee frames.Dit betekent dat in plaats van je animatie er in slow motion zo uitziet:
... het zou er als volgt uitzien:
Nemen dat, blitting!
Bonusstap: kleurenmatrix
Als u Flash gebruikt om te animeren, ziet uw kleurenmatrix er ongeveer zo uit:
1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0
Niet echt leesbaar nu?
Flash slaat daar alle gegevens over helderheid, contrast en verzadiging op. Gelukkig hebben ze hun formule geüpload, zodat we dit niet hoeven proberen te reverse engineeren.
De onderstaande formule vertelt u hoe u de uiteindelijke RGBA-waarden van de pixel berekent op basis van de bronkleur en de kleurenmatrix (
een
is de matrixkleur matrix):redResultaat = (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] alphaResultaat = (a [15] * srcR) + (a [16] * srcG) + (a [17 ] * srcB) + (a [18] * srcA) + a [19]Meer informatie over Flash's
ColorMatrix
klas is hier te vinden.
Conclusie en case study
Hoewel het in het begin misschien een beetje eng lijkt, is deze methode dat wel werkelijk gemakkelijk te gebruiken wanneer alles is ingesteld, en het opzetten van een goede basis is wat tijd en moeite waard.
Dat wil niet zeggen dat deze methode ideaal is voor elke situatie. Zoals eerder vermeld, als je game afhankelijk is van frame-voor-frame animatie of dingen die niet gedaan kunnen worden met tweening, zou dit niet echt werken. (Hoewel je altijd methoden kunt mixen en matchen.)
Met dat gezegd, laten we een kijkje nemen naar een laatste echt voorbeeld van het gebruik van deze methode.
Dit is een deur:
Het opent en sluit en je wilt dat de speler er niet doorheen kan.
Het is eenvoudig, toch? U zou alleen een aanvaringskader verticaal laten bewegen, afhankelijk van hoeveel frames er door de animatie zijn. Het probleem is echter dat deze animatie niet lineair is: er is enige lichte versoepeling. Door de verticale positie van de collision box aan te passen aan het huidige frame van de animatie, zou de aanvalsbox niet synchroon lopen met de animatie, waardoor het lijkt alsof ze door de deur gaan of op dunne lucht staan.
Gelukkig heb je de
X
,Y
,hoogte
enbreedte
van het geanimeerde deuritem, zodat u uw botsing perfect kunt synchroniseren!
Blitten versus activabladen