PlanetSwitch Planet3DS PlanetVita PSP.de PlanetiPhone Classics Forum

PGN-ID:[?] (Nicht eingeloggt)
Login
Registrieren
PlanetDS PlanetGameboy N-Page.de

dumme Tutorials Teil 3: Animations-Schemen

zurück

Autor: dummer Anfänger

Kategorie: devtut
Umfang: 1 Seiten

Seite   1  

Kommentare:

Kommentieren (-)

Game Boy Advance Artikel vom 09.10.2002








Animationsschemen








[Wiederholung:
Was bisher geschah
]

[Überlegung: Was brauchen wir?]
[Realisierung] [Erstellen der
Funktion
]
[Arbeiten mit der Funktion] [Beim nächstem mal]
























Autor: dummer
Anfänger
Erstellt: 09.Okt.02
Level: Fortgeschrittene
Kenntnisse:
Strukturen

vorheriges Tuto.













Und schon wieder ist es passiert:
noch ein dummes Tutorial.

Dieses mal kommen wir endlich zu einem Thema das bei einigen die Augen glitzern
lässt: Wir lassen unser Sprite laufen!



Ja eigentlich noch ein wenig
mehr. Ich werde mit euch in diesem Tutorial eine Möglichkeit erarbeiten die es
uns erlaubt einfach nur noch "Sprite: LAUF" zu sagen und das Ding macht den Rest
praktisch automatisch. Dazu kommt dann noch das wir Kommandos wie "Lauf" oder
"Spring" selbst möglichts einfach erzeugen wollen. Schließlich müssen wir dann
noch irgend wie damit klar kommen dass unsere Animationen nicht immer den selben
Ausgangspunkt haben und wir damit unser Sprites nicht zucken irgend etwas
dagegen unternehmen müssen.




Dieses Tutorial wurde von mir in der
Absicht geschrieben Leuten zu zeigen wie man mit dem GBA von der Firma Nintendo,
die alle Rechte an dem GBA und der kommerziellen Veröffentlichung von GBA
Spielen besitzt, umgeht und mit Hilfe anderer Software dafür Programmiert. Ich
gebe keinerlei Garantie das was ich euch hier zeige Funktioniert und übernehme
keinerlei Haftung für Schäden die eventuell bei euch entstehen während ihr
dieses Tutorial durcharbeitet ^^.

Dieses Tutorial richtet sich an Programmierer. Dies bedeutet das ihr die Sprache
"C" beherrschen müsst und darüber in klarem sein solltet was ein Pointer ist.
Auch gehe ich davon aus das ihr bereits in den anderen auf
www.devgba.de erhältlichen Tutorials
geschmökert habt und das dort beschriebene Fachwissen beherrscht. Ihr solltet
wissen was Duale und Hex-Zahlen sind, den Unterschied zwischen Bit und Byte
kennen sowohl als auch in der Lage sein diese Werte zumindest mit einem
Taschenrechner umzuwandeln. Auf Fragen die
eine Programmiersprache selbst bzw. das dort beschriebene Wissen betreffen werde
ich nur ungern Antwort geben bzw. euch wahrscheinlich barsch die URL geben damit
ihr es selbst lesen könnt. Sachen die in deutsch nicht verfügbar sind werden
jedoch gerne von mir, so wahr ich es kann, beantwortet. Überall im Text sind
jedoch genaue Quellenangaben zu sehen wo man sich genauer darüber erkundigen
kann.





Wiederholung: Was bisher geschah


Im letztem Tutorial haben wir uns
viele Gedanken darum gemacht wie der Aufbau eines Sprites
ist und wie wir unser Sprite wohl am einfachsten Animieren
könnten.


Dazu haben wir uns eine kleine
aber feine Funktion geschrieben mit der wir die Sprite-Grafik austauschen
können. Egal wo sie ist und wie groß sie ist denn darum kümmert sich die
Funktion netterweise selbst.

Bei der Erstellung dieser Funktion haben wir viele Nette kleine Sachen kennen
gelernt. Darunter das Schieben und die Boolischen
Verknüpfungen AND und OR
(UND - ODER) die auch dieses mal wieder mit von der Partie sein werden.


Alles in einem hatten wir viel
Spaß und ich denke nachdem wir ende dieses Tutorials auch etwas damit
anfangen können werden wir noch mehr Spaß haben.






Überlegung: Was brauchen wir?


Am Anfang wenn man etwas neues
Programmieren sollte muss man sich erst einmal darüber in klarem werden was man
überhaupt machen will. Nun, ich denke das wissen wir ganz genau: Wir wollen
unser Sprite zum laufen kriegen! ^^


Ok, das haben wir uns ein wenig
leicht gemacht also sagen wir es etwas genauer: Wir wollen
das unser Sprite und auch andere Sprites bestimmte Bewegungsabläufe ausführen
können.



Was brauchen wir damit unser Sprite
läuft?


Laufen tut es ja im Prinzip auch schon in unserem letzten Beispiel. Würden wir
dort noch schnell die y Werte verändern würde unser kleines Sprite artig von
oben nach unten laufen und würden wir dann alles per Hand so fummeln dann könnte
man es sicherlich auch steuern.


Sicher toll für die Grundlagen
und eine Demo, jedoch ist es ja unser Ziel die Sprites später in einem Spiel zu
haben. Wir können es uns nicht leisten alles per Hand zu machen denn schon bei
zwei Figuren verliert man dabei den Verstand...


Überlegen wir daher einmal
logisch welche Features ein Animations-Schema bräuchte nach dem ein Sprite
laufen kann.




  1. Es muss reichen wenn wir sagen
    "Lauf" und der GBA weiß was er zu tun hat.



  2. Es gibt
    zwei Schemen
    : Einmal eine Aktion die unterbrochen werden kann (laufen
    zum Beispiel) und zum anderen etwas das bis zum Bitterem Ende fortgeführt wird
    zum Beispiel ein Schlag.



  3. Wir müssen irgend wo festlegen
    welche Animationen unser Sprite bei dieser Aktion macht und wie viele das
    sind.



  4. Unser Sprite muss sich bei der
    Aktion eventuell vorwärts Bewegen. Mehr noch, vielleicht macht er ja einen
    Satz zurück und springt erst dann nach vorne.



  5. Wir müssen damit rechnen das
    unsere Animationen nicht perfekt zusammen passen da sie ja sonst nicht in das
    Sprite passen würden und wir ein größeres Sprite benutzt hätten. Auch dies
    müssen wir ausgleichen.



OK ....

Nach dem erstellen einer solchen Auflistung ist es bei professionellen
Programmierern üblich erst einmal eine weile den Monitor bzw. das Notizblatt
anzustarren und sich verzweifelt zu Fragen wie man das wohl umsetzen könnte.


Wir stellen schließlich fest das wir alles haben was
wir für unser Animations-Schema brauchen jedoch bleiben viele andere Fragen
ungeklärt.

Woher soll unser Sprite wissen
welches Schema es gerade durchläuft? Woher soll es später überhaupt wissen in
welche Richtung es schaut? Ob es schwimmt oder fliegt? Fragen über Fragen denn
Fakt ist: Die GBA Hardware kümmert sich nur um das Anzeigen von Bildern die wir
hier Sprites nennen doch dies ergibt noch lange keine Figur.

Obwohl wir ja eigentlich nichts
weiter wollten als unser Sprite laufen lassen sind wir nun doch gezwungen die
Eigenschaften des Sprites zu erweitern damit wir überhaupt die Möglichkeit haben
unsere Animations-Schemen sinnvoll anzuwenden.

Was benötigt also eigentlich eine Figur in unserem Spiel?



  1. Sie muss wissen welches Hardware
    Sprite zu ihr gehört.



  2. Sie muss wissen ob sie gerade in
    einem Schema ist. Optimal währe es wenn sie noch weiß in welchem.



  3. Sie muss wissen wie weit sie,
    ggf. das Schema schon durchlaufen hat.



  4. Wir sollten wissen wie wichtig
    das ist was das Sprite gerade macht. Gehen wird schon unterbrochen wenn man nur
    eine Taste loslässt. Ein Sturz z.B. nicht. Das ist aber Sache des jeweiligen
    Spieles und interessiert uns im Moment nicht.



  5. Schwimmt unser Sprite? Fliegt es?
    Auch das ist Sache des Users aber wird dennoch benötigt.



  6. In welche Richtung schaut unser
    Sprite?



  7. Wir sollten noch eine Variable
    übrig lassen in die wir einen Pointer machen können. Auf was wissen wir im
    Moment zwar nicht aber später würde sich da vieles anbieten wie z.B. die zur
    Figur gehörende Lebensenergie.



Toll. Unfreiwillig ist unser
Sprite nun größer als das eigentliche Schema das wir erstellen wollen -_-;

Naja was soll es. Ich hoffe nur das diese beiden Strukturen sich später im Spiel
auch bewähren und nicht mehr als zu sehr verändert werden müssen.... Lieber
lange geplant als lange verbessert.






Realisierung


Genug gefrustet. Versuchen wir
unsere Anforderungen einmal in Programmierbare Tatsachen um.


Wir wollen bei den
Animations-Schemen 5 Wünsche auf einmal erledigt haben. Das können wir mit einer
einzelnen Variable natürlich nicht. Daher werden wir unser Schema jeweils in einer
Struktur unterbringen.



Eine Struktur ist in etwa das
selbe wie eine einzelne Variable. Wir können sie genauso behandeln jedoch
enthält sie immer mehrere Datensätze auf einmal. So wie praktisch zu einem guten
Pokemon-Set ein GameBoy und ein paar Spiele auf einmal gehören (scheiß
Beispiel). Mehr Infos dazu auf Anfrage, doch schaut euch einfach mal an wie wir
es machen. Vieles erklärt sich von selbst.




Sind wir also schon beim dritten
Schritt: Welche Animationsphasen (und wie viele) soll unser Sprite machen?

Dazu speichern wir also erst einmal klar ab wie viele


Phasen
wir überhaupt
durchlaufen.

Die Animationsphasen selbst speichern wir danach einfach in einem
Array ab. Es genügt wenn wir für die jeweilige
Animationsphase stellvertretend nur eine Zahl speichern die wir mit unserer
Animate Funktion aus dem setzten Tutorial benutzen
können.

Die beiden letzten Punkte auf unserer Liste lassen sich beim näheren hinsehen
sehr gut zusammenfassen. Wenn wir eh die Verschiebung unseres Sprites
definieren müssen können wir diesen Wert auch gleich mit dazu benutzen unsere
Unregelmäßigkeiten auszubessern. Dazu machen wir also zwei Werte (x und y
logischerweise) die dann immer angeben um wie viel sich unser Sprite bei dieser
Animationsphase wohin bewegt.


So. Grob über den Daumen gefeilt
kommen wir also zu etwa diesem Ergebnis: Unsere Struktur
aSchema






typedef struct
aSchema {

u8 phasen;



u16 aPhase[8];



s8 xvar[8];

s8 yvar[8];

};



Mit dieser können wir nun also
eine Animation beschreiben die maximal 8 Phasen haben kann. Gerne auch mehr (bis
256) dazu müsst ihr einfach nur die Arrays größer machen welche beschreiben wie
viele Daten wir umfassen wollen.

Die Werte für die x und y Variation sind beide jeweils
signed, heißt also sie
sind von -128 bis 128 setzbar. Für unseren Zweck also ganz genau richtig.


Hui. Nun wo die Struktur steht
sieht das ganze doch wirklich noch einfacher aus als es zuerst den Anschein
hatte ;) kommen wir also zu der Sprite Erweiterung.








typedef struct
gameSprite {

u8 sIndex;

aSchema* running;

u8 step;



u8 proirity;

u8 ido;

u8 ilook;

u32 point;

}gameSprite;



Das ist sie, frei heraus
gedonnert. Ich habe das ganze, unglaublich kreativ wie ich bin,
gameSprite genannt.

Die ersten drei Atribute sind wie vorher in der Liste schon überlegt einmal der
Index zu unserem Hardware Sprite (Dovoto Standart),
dann ein Eintrag der uns sagt welches Schema gerade läuft
(ansonsten 0) und zuletzt wie weit wir im Schema schon
fortgeschritten sind
.

Die unteren 4 Atribute hingegen enthalten Variablen mit denen der User im
jeweiligen Spiel anders umgehen muss und kann. Allein die
Priorität
hat für uns im Moment in sofern Bedeutung das sich unsere
Schemen falls diese 0 ist von allein wiederholen sollen.







Erstellen der Funktion



Fast geschafft. Der Theorie nach
müssten die beiden Strukturen wie geplant funktionieren.

Wollen wir nun also mal eine Funktion schreiben mit der wir das ganze
schließlich auch ausprobieren können.


Welche Variablen brauchen wir?

Da brauchen wir wohl als erstes einmal unser gameSprite. Da dieses wie die
Hardware Sprites nicht von Anfang an in einem Array ist benötigen wir davon den
Pointer.

Dann wollen wir wissen welches Schema wir ausführen wollen. Logisch, gell?

Zuletzt müssen wir noch wissen mit welchen Bilddaten das ganze passieren soll.




void
exec_schema(gameSprite* sp, aSchema* schem,
u16
* BitmapData);


.. macht doch einen guten
Eindruck, oder?


Durchlauf der Funktion.

Allem voran sollten wir prüfen ob dieses Animations-Schema bereits läuft. Ist
dem so machen wir dort weiter wo wir aufgehört haben, ist dem nicht so beginnen
wir von vorn. Codemäßig sieht das in etwa so aus:



if
(sp->running
!= schem) {

sp->step = 0;

sp->running = schem;

}


Haben uns darum gekümmert können
wir im Prinzip bereit die Bilddaten des Sprites ändern. Endlich kommt meine
coole Animate Funktion zum zuge ^^



animate_cpu(sp->sIndex,
BitmapData, schem->aPhase[sp->step]);


Was ein Wirrwar! Also wie ihr
sehen könnt bedienen wir uns bereits in vollen Zügen den übergebenen Daten. Da
währe einmal der Sprite Index von sp, der
Pointer der bereits ein Pointer ist und daher
einfach nur übergeben werden muss (macht blos kein &) und zum Schluss die
aktuelle Animationsphase.


Nun haben wir also das Bild
ausgetauscht und es wird Zeit das wir auch die x und y Position
des Sprites so verändern wie wir sie uns wünschen. Dazu addieren wir einfach die
gespeicherten Werte auf das jeweilige Register drauf wodurch wir automatisch die
richtige Verschiebung nach links oder rechts erhalten.

Dadurch das wir einfach nur drüber
addieren kann es natürlich bei zu hohen Werten zu überträgen kommen. Wer später
Angst hat vor solchen Überträgen der kann hier ja noch eine
If Anweisung hinzufügen die solch einen Fehler
abfängt.



sprites[sp->sIndex].attribute1 +=
schem->xvar[sp->step];

sprites[sp->sIndex].attribute0 += schem->yvar[sp->step];


Gut gut! Natürlich sollten wir
zwei Sachen am Ende nicht vergessen. Zum einem das wir eine Animationsphase
weiter schalten müssen und zum anderem danach zu schauen ob die Animation damit
vollendet ist.

Wir erinnern uns das wenn das Atribut

running
im
gameSprite
0 ist das unsere Animation darauf vorbereitet wird das sie
beim nächstem mal einfach von vorne beginnt. Ist dem nicht so schließen wir das
Schema indem wir unseren Pointer löschen.



if(sp->step
>= schem->phasen) {

if(sp->proirity==0)
sp->step=0;

else sp->running = 0;

}


Hier nun die komplette Funktion
auf einem Blick:







void exec_schema(gameSprite*
sp, aSchema* schem, u16* BitmapData) {

if(sp->running !=
schem) {

sp->step=0;

sp->running = schem;

}



animate_cpu(sp->sIndex,
BitmapData, schem->aPhase[sp->step]);



sprites[sp->sIndex].attribute1 += schem->xvar[sp->step];

sprites[sp->sIndex].attribute0 += schem->yvar[sp->step];




sp->step++;



if(sp->step >=
schem->phasen) {

if(sp->proirity==0)
sp->step=0;


else
sp->running = 0;

}

}






Arbeiten mit der Funktion



So ... schließlich haben wir es
geschafft: Unsere Funktion und alle dafür notwendigen Strukturen stehen.

Ein ordentliches Stück denn anders als in dem letzten Tutorial haben wir ja
dieses mal auch eine ganze Menge eigener Strukturen erstellt von denen wir
hoffen das sie später im Spiel genauso praktisch laufen wie wir es uns erhoffen.

Sagen kann man das leider vorher nie so genau. Es kommt halt auf den Versuch an
;)


Doch eben weil dieses mal die
Anwendung nicht ganz so klar ist wie das letzte mal wollen wir hier nun noch
einmal zusammen ein Beispiel durchgehen wir wir unser Sprite vom letzten mal
dieses mal den Bildschirm herunter laufen lassen.

Zugegeben: Dieses Beispiel liegt weit, sehr weit, unter dem eigentlichen
Potential der Animations-Schemen doch soll es euch ja auch nur kurz zeigen wie
wir überhaupt ein Schema erstellen.


Also als erstes machen wir wie im
Sample des letzten Tutorials unser Sprite und die üblichen Bildschirm
Einstellungen, setzen Zähl Variablen und laden die Palette ein usw.




u16
index = 0;

u16 loop = 0;



SetMode(MODE_2 | OBJ_ENABLE | OBJ_MAP_1D);



for(loop = 0; loop < 256; loop++)
OBJPaletteMem[loop] = sprite_animaPalette[loop];



InitializeSprites();



sprites[5].attribute0 = COLOR_256 | SQUARE | 12;

sprites[5].attribute1 = SIZE_32 | 40;

sprites[5].attribute2 = 666;


Dann jedoch erstellen wir noch
unser gameSprite und legen es auf das 6. Hardware Sprite fest das wir zuvor
eingerichtet hatten.



gameSprite mySprite;

mySprite.sIndex = 5;


Gut. Nun erstellen wir unser
erstes Animations-Schema.

Es wird 6 Phasen haben, bei jeder das Sprite einen Pixel weiter herunter bewegen
und linear die Animationen in unseren Bilddaten durchlaufen.



aSchema runter;

runter.phasen=6;



runter.aPhase[0]=0;

runter.yvar[0]=1;



runter.aPhase[1]=1;

runter.yvar[1]=1;



runter.aPhase[2]=2;

runter.yvar[2]=1;



runter.aPhase[3]=3;

runter.yvar[3]=1;



runter.aPhase[4]=4;

runter.yvar[4]=1;



runter.aPhase[5]=5;

runter.yvar[5]=1;


Nun schnell noch eine billige
Schleife mit der wir unsere Animation wieder und wieder und wieder durchlaufen
lassen.




while
(1) {

if(loop>60) {


exec_schema
(&mySprite, &runter, &sprite_animaData);


CopyOAM
();

loop=0;

}

loop++;

WaitForVsync();

}


Fertig. Es ist natürlich ratsam
wenn man sich mal eine Animations-Schemen Sammlung gemacht hat diese zusammen
mit den dazugehörigen Bilddaten in einen Header File auszulagern...







Beim nächstem mal





Uff.. Geschafft. Dieses mal hab ich mich mit dem
Tutorial doch wesentlich schwerer getan als das letzte mal.

Ich hoffe das es dennoch halbwegs verständlich ist. Ich weiß das es ein riesiger
Textblock ist da dieses mal keine Bilder dazwischen sind und ich weiß das dieses
mal der Beispielcode etwas spartanisch sein mag.. Aber ich hoffe dennoch das ich
euch damit ein mächtiges Tool für eure zukünftigen Spiele in die Hand gedrückt
habe mit dem ihr halbwegs lernt umzugehen.


Wo wir gerade beim Umgehen sind.

Speziell nun wo wir ja wirklich eine Methode kreiert haben mit der wir
Animationsabläufe speichern kann währe es umso wünschenswerter ein Tool zu haben
mit dem man einfache Grafiken komfortabel umwandeln und gleich noch eben diese
Schemen Visuell bearbeiten könnte.

Ich hoffe ja immer noch einen Deppen zu finden der mir diese Arbeit abnimmt . .
. Sollte mir das jedoch nicht gelingen werd ich es wahrscheinlich selbst
schreiben müssen.


Im nächsten Tutorial haben wir dann erst einmal
genug von Sprites und setzen uns mit Map's auseinander.

Bis zum nächsten Tutorial wird es daher etwas länger als nur eine Woche (einen
Monat vielleicht?) dauern...



Aber woher soll ich schon wissen wie das alles
geht? Ich bin ja nur ein dummer Anfänger ;)


Bis zum nächstem mal.



Downloads:

Die Funktion und Beispielcode



< vorige Seite Seite   1   nächste Seite >