[Pokémon Feurrote Edition] Eingebaute OAM-Funktionen (GBA-Sprites)

  • Hi Leute,


    heute möchte ich euch etwas vorstellen, das mich einige Zeit des Researchens gekostet hat, jedoch von nicht geringer Relevanz und Mächtigkeit ist. Die Rede ist davon, OAMs (das sind Objekte auf dem Bildschirm) zu animieren oder bessergesagt, welche eingebauten Mechanismen das Spiel hat, diese Animationen zu schreiben. Glücklicherweise sind sie nämlich nicht alle hardcoded.


    1. Einführung in die OAMs


    Ein OAM ist wiegesagt ein Objekt, das auf oder zwischen den 4 BGs liegt. Zu diesen Objekten zählen beispielsweise auch die Overworlds. OAMs greifen - im Gegensatz zu den BGs - nicht auf das Tileset-Tilemap Prinzip zurück, wenn es darum geht, wie ein solches Objekt aussieht. Stattdessen wird eine ganze Grafik als "Tileset" an irgendein VRAM-Offset geladen (es bleiben weiterhin 8x8 Tiles) und diese ganze Grafik wird dann 1:1 auf den Bildschirm als Objekt gemappt. Die Position dieser Grafik im VRAM bezeichne ich im Laufe des Tutorials als "start_tile". Welches start_tile ein OAM nun benutzt, wird in seinen Attributen festgelegt.
    Jeder OAM hat ein 6-Byte Attributfeld, in dem seine Attribute bitweise gecodet sind (Position, Priorität, Form, Größe, Palette, etc.). Natürlich ist es ziemlich hässlich, auf ein solches 6-byte Feld jedes mal bitweise zuzugreifen und damit zu rechnen. Das Spiel hat deshalb eine Mechanik, die den Zugriff auf OAMs erleichtern soll, eingebaut.
    Jeder OAM besitzt im WRAM nun eine 0x44-Byte-Struktur, welche seine Attribute festlegt. Jeden Frame errechnet das Spiel dann aus dieser Struktur die 6-Byte Attributstruktur und schreibt diese ins OAMRAM. Das heißt, wir als Hacker, müssen uns im Grunde nur mit der 0x44-Byte-Struktur auseinandersetzen. Die Struktur ist wie folgt aufgebaut (nur weil ihr jetzt nicht alles versteht, müsst ihr nicht aussteigen - dieser Part ist sowieso nicht zentral).



    Über diese Struktur können wir einen OAM beliebig manipulieren und generieren. Aber nicht einmal das müssen wir erledigen, denn auch dafür stellt uns dsa Spiel eine Routine bereit. Diese Routine nenne ich "spawn_oam" (FRD-Offset: 0x6F0C). Die Routine erhält folgende Übergabewerte und erzeugt einen neuen OAM:



    Nun ist erneut der Begriff template gefallen. Was ist diese template also? Das template meint eine Vorlage, eine Struktur, die Informationen über den OAM enthält. Diese Struktur ist 24 (0x18) Bytes groß und setzt sich aus folgenden Attributen zusammen:


    In dieser Struktur legen wir die Attribute fest, die unser OAM später haben soll. Besonders wichtig für diese Tutorial sind die GFX- und Rotscalanimationstabellen, sowie die GFX-Tabelle. Jedoch sind auch in der 6-Byte Struktur wichtige Informationen enthalten, die wir leider bitweise encoden müssen. Dort legen wir fest, ob unser Objekt Rotation/Skalierung überhaupt nutzen will und außerdem, zudem auch Größe, Form und Palette (sollte sie keine getaggte Palette hernehmen).




    2. Einführung in die GFX-Strukturen


    Was ist eine GFX-Struktur? Ganz einfach, ein GFX ist eine 8-Byte-Struktur, die ein Bild enthält. Dieses Bild ist entweder lz77-komprimiert oder liegt direkt als Bitmap im ROM vor. Dieses Bild kann dann als Grafik für einen OAM-Verwendet werden. Üblicherweise erhalten alle GFXs einen Tag, eine Nummer, die sie eindeutig identifziert. Wenn wir also eine neue GFX-Struktur erstellen wollen, müssen wir uns auch einen Tag überlegen (es gibt ja gerademal gut 65 000 Möglichkeiten, da wird euch schon etwas einfallen). Eine GFX-Struktur sieht also wie folgt aus:


    Eine GFX-Tabelle ist dann nichts anderes, als eine Liste von Pointern, die jeweils auf ein GFX-Element zeigen.






    3. GFX-Animationen


    Nun kommen wir endlich zum Kern der Sache - den Animationen. Der erste eingebaute Animationstyp bezieht sich nämlich auf die GFX-Strukturen eines OAMs. Zuerst jedoch müssen wir differenzieren, da es zwei verschiedene Typen von GFX-Animationen gibt.

    • GFX Animationen, bei denen alle Animationsframe in einem Sprite enthalten sind: Der OAM nutzt nur ein einziges GFX-Objekt. Diese Animation wird dann ausgeführt, wenn im OAM template ein GFX-Tag angegeben ist, da er sich ausschließlich auf dieseen bezieht. Die GFX-Tabelle ist für eine solche Animation irrelevant und darf deswegen auch ein Nullpointer sein.
    • GFX Animationen, bei denen sich die Animationsframes in seperaten GFXs befinden: Der OAM nutzt eine ganze Tabelle von GFX-Objekten. Dabei müssen alle Sprites als Bitmaps vorliegen. Diese Animation wird dann ausgeführt, wenn im OAM template 0xFFFF als GFX-Tag angegeben ist.

    Für beide Fälle ist eine GFX-Animation jedoch gleich aufgebaut: Sie besteht aus einer Abfolge von verschiedenen GFX-Frames. Diese GFX-Frames sind jeweils 4 Bytes groß. Sie unterscheiden sich jedoch im Aufbau, jenachdem, welcher GFX-Animationstyp vorliegt.
    Fall 1:
    Da der OAM sich auf ein einziges GFX-Objekt bezieht, wird dieses beim Erzeugen des OAMs direkt ins VRAM an eine freie Stelle dekomprimiert und das start_tile sofort auf die richtige Zahl gesetzt. Nun befinden sich bereits zum Zeitpunkt des ersten durchführens der Animation alle grafischen Ressourcen im VRAM, sodass diese über die Tile_IDs angesprochen werden können. Ein Beispiel: Mein Sprite enthält nacheinander 4 32x32 Bilder, die jetzt alle ins VRAM an die Position tile_id geladen wurden. Die Position des ersten Bildes wäre demnach tile_id+0, die Position des zweiten Bildes tile_id+ (32 x 32 / 2 = 512), die Position des dritten Bildes tile_id + 1024, etc. Und diese Tatsache, dass sich alle Ressourcen bereits im VRAM befinden, macht sich diese Animationsart zunutze. Was jedoch gesagt werden muss: Für Bilder, die größer als 16x16 sind, eignet sich das eher nicht - so viel Platz hat der ObjVRAM gar nicht.
    Betrachten wir, da wir das nun wissen, also den Aufbau eines Frames:

    Code
    1. [ information (2 bytes)] [wartezeit nach ausführung (2 bytes)]


    • Information gibt an, um wie viele Tiles start_tile von seiner Ursprungsposition aus verschoben werden soll. Will ich also den zweiten Frame haben, bräuchte ich dort den Wert 512 (0x200). Will ich den dritten Frame haben, bräuchte ich den Wert 1024 (0x400), etc. Der Wert ist auf 10-Bits beschränkt, was eine Reichweite von 0x0 - 0x3FF ermöglicht. (Größer ist der ObjVRAM auch nicht, weswegen dieses Verfahren für eine 32x32 Grafik nicht zu empfehlen ist).
    • Warezeit enthält zwei Informationen: Bit 0-5 enthalten eine Wartezeit in Frames, die nach Ausführung der Verschiebung erfolgt. Bit 6,7 enthalten boolsche Werte, die angeben, ob das Bild horizontal und/oder vertikal gespiegelt werden soll. Dabei steht 1 für eine Spiegelung und 0 für keine Spiegelung.

    Die Ausnahme bilden die sogenannten Steuerbefehle, die die Animation steuern können:

    Code
    1. [Steuerbefehl (2 bytes)] [Parameter (2 bytes)]


    Folgende Steuerbefehle existieren:

    • 0xFFFC: Markiert den Beginn einer Schleife: Parameter wird ignoriert und es wird sofort der darauffolgende Befehl ausgeführt. (Diese Art der Schleifen ist NICHT zu empfehlen, da sie alle Animationen des OAMs resettet)
    • 0xFFFD: Springt zum vorherigen Schleifenbeginn und setzt die Animation komplett zurück (auch die Rotscal-Animation)
    • 0xFFFE: Springt zum Frame mit dem Index [Parameter]. Für Endlosschleifen zu empfehlen.
    • 0xFFFF: Beendet die laufende Animation.

    Hier eine Beispielanimation:

    Code
    1. 0x0000 0x0020 0x0040 0x0028 0x0060 0x0068 0xFFFE 0x0000


    Sie würde folgendes bewirken: Zuerst für 32 Frames start_tile+0 (erster Frame). Dann für 40 Frames start_tile+64 (zweiter Frame). Dann für 40 (bit 0-5 in 0x68 sind 0x28) Frames start_tile+96 (dritter Frame). Außerdem horizontal spiegeln (Bit 6 in 0x68 ist 1). Dann wieder zurück zum ersten (0-ten) Befehl in der Animation zurückspringen (also für 32 Frames start_tile+0). Das würde eine Endlosanimation hervorrufen, die aktiv ist, solange der OAM gezeigt wird.

    Wo war Gondor, als meine Klausurenphase begann?

    Edited once, last by Wodka ().

  • Fall 2:


    Der OAM bezieht sich nicht auf ein festes GFX-Objekt, sondern eine GFX-Tabelle (GFX-Tag im oam_template ist 0xFFFF). Der OAM benutzt also verschiedene Sprites, die er, wenn sie benötigt werden, immer neu ins VRAM lädt und damit den alten Sprite überschreibt. Aufgrund von Performancegründen fordert das Spiel hier deswegen auch unkomprimierte Sprites (Kopieren ist schneller als dekomprimieren). Die Syntax jedoch ähnelt der des Falls 1 ungemein. Wieder hat ein GFX-Frame die Länge 4 bytes:

    Code
    1. [Information (2 bytes)] [Wartezeit nach Ausführung (2 bytes)]


    Die Information enthält diesmal jedoch keine Verschiebung in Tiles, sondern einen Index. Dieser Index gibt an, welches Element aus der GFX-Tabelle kopiert werden soll. Angenommen der Index wäre 0x2, dann würde das 0x2te GFX-Objekt aus der GFX-Tabelle ins VRAM kopiert und angezeigt.
    Die Wartezeit setzt sich exakt so zusammen, wie in Fall 1 (auch mit Spiegelung).


    Ein Beispielscript erspare ich mir an dieser Stelle, da die Analogie zu Fall 1 nicht zu übersehen ist.



    4. Rotscal-Animationen:


    Rotation und Skalierung: Nun kommen wir zum zweiten Animationstyp: Rotation und Skalierung. Auch für diese existiert eine eingebaute Animationssprache (für die, die es nicht wissen: Mit Rotation/Skalierung können wir ein OAM-Objekt drehen und vergrößern/verkleinern). Zunächst müssen wir aber auch gewährleisten, dass unser OAM Rotation/Skaleriung unterstützt. Das wird in der 6-Byte Struktur final_oam definiert (siehe GBATEK unter Oam-Attribute-0). Auch die Double-Size-Flag können wir hier verwalten. Diese weißt unserem Objekt, wenn sie gesetzt ist, einen doppelten Darstellungsbereich zu. Das ist insofern wichtig, dass wenn wir unser Objekt vergrößern, es immer noch auf seiner usprünglichen Größe dargestellt werden würde (ein 64x64 Objekt würde, auch wenn es um den Faktor 1,5 vergrößert wurde, noch immer in einen 64x64 Kasten gequetscht sein).
    Rotations/Skalierungs-Animationen werden nur ausgeführt, wenn die Rotations/Skalierungsflag gesetzt ist.


    Eine Rotscal-Animationstabelle enthält - analog zur GFX-Animationstabelle - lediglich eine Liste von Pointern auf Rotscal-Animationen. Eine Rotscal-Animation an sich ist wieder - auch hier analog zur GFX-Animation - aus einzelnen Rotscal-Frames aufgebaut. Diese unterscheiden sich jedoch in Größe und Struktur von den GFX-Frames.


    Ein Rotscal-Frame besteht aus 8 Bytes, die wie folgt strukturiert werden:

    Code
    1. [xscal (2 bytes)] [yscal (2 bytes)] [rotation (1 byte)] [duration (1 byte)] 0000


    • xscal und yscal stehen dabei für einen Kommazahlwert, der den Faktor angibt, um wie viel der OAM in eine Richtung vergrößert/verkleinert werden soll. Dabei stehen bit 0-7 für die Nachkommastellen und bit 8-15 für den Integer-Teil. So würde z.B. 0x100 den Wert 1.0 , 0x200 den Wert 2.0 , 0x80 den Wert 0.5 , 0xC0 den Wert 0.75 , 0x1C0 den Wert 1.75 , etc. darstellen. Wichtig ist, dass pro Frame um + diesen Wert weiter skaliert wird. Wenn also der Startwert 0x100 ist, so würde 0x2 auf 0x20 Frames am Ende einen Skalierungsfaktor von 0x140 oder auch 1.25 bedeuten.
    • rotation gibt an, um welchen Winkel das Bild pro Frame gedreht werden soll.
    • Duration gibt die Zeitdauer des Rotscal-Frames an: Innerhalb dieses Zeitintevervalls wird die Skalierung auf z.B. 0x180 so aufgeteilt, dass sich ein flüssiger Ablauf ergibt und am Ende des Frames das Bild auf 0x180 skaliert wurde. Für die Rotation gilt, dass für jeden Frame innerhalb des Rotscal-Frames das Bild um rotation gedreht wird. Gibt man also für rotation 0x40 (90 Grad) an und beträgt die Dauer 32 Frames, so wird das bild um 90*32 Grad gedreht und jeden Frame um 90 Grad (was bei 60 fps Augenkrebs erregt). Rotation gibt also - im Gegensatz zu dem Skalierungswerten - nicht die Gesamtrotation an, sondern die Rotation jeden Frame!

    Auch für diese Animationen existieren wieder Steuerbefehle:
    Für sie sieht der Aufbau wie folgt aus (Länge ist nach wie vor 8 bytes):

    Code
    1. [befehl] [parameter] 0000 0000


    • 0x7FFD: Markiert den Beginn einer Schleife, wenn das Rotscalfeld3 auf 0 gesetzt ist (was es zu beginn der Animation ist) / Springt zum markierten Schleifenbeginn und setzt das Rotscalfeld3 auf den Wert von [parameter]
    • 0x7FFE: Springt zum Animationsframe mit dem Index von [parameter] (für Endlosschleifen wieder zu empfehlen)
    • 0x7FFF: Beendet die laufende Rotscal-Animation

    Hier wieder ein Beispielscript:

    Code
    1. 0x0004 0x0004 0x02 0x40 0x0000 0x0100 0x0100 0xFFFB 0xFFFB 0xFD 0x40 0x0000 0x7FFE 0x0000 0x0000 0x0000


    Der Script würde folgendes bewirken: Innerhalb von 0x40 Frames wird der OAM um den Faktor 2,0 in X- und Y-Richtung skaliert und außerdem um 180 Grad gedreht. Dann wird der OAM innerhalb von 0x40 Frames wieder auf den Faktor 1,0 zurückskaliert und um -180 Grad gedreht. Das ganze wiederholt sich dann in einer Endlosschleife.
    5. Korrektes Despawnen eines OAMs
    Nun habe ich viel darüber geredet, wie man einen OAM erzeugt und animiert. Jedoch gibt es auch beim Despawnen, also dem "Verschwinden-Lassen" eines OAMs einiges zu beachten. Die Funktion "spawn_oam" spuckt nämlich als Rückgabewert in r0 eine ID aus, über welche man auf den OAM-Buffer zugreifen kann. (Für FRD: ID*0x44 + 0x0202063C = OAM-Buffer Offset).
    Weiterhin existiert auch eine Routine, die ich "clear_oam" genannt habe. Sie löscht den gesammten OAM-Buffer, sodass dieser wieder benutzt werden kann (FRD-Offset: 0x735C) und erwartet als Parameter das Buffer-Offset.


    Nun haben wir jedoch, wenn wir uns GFX-Animationen, Rotscal-Animationen (und auch Palallozierung) zunutze machen, einige Probleme:

    • GFX: Das Spiel sucht im VRAM nach einem geeigneten Platz für unsere Grafik und markiert diesen Platz dann als belegt (Allozierung). Dieser Platz wird aber nicht automatisch wieder freigegeben, wenn man clear_oam aufruft.
    • Rotscal: Es existeren 32 Gruppen, welche Werte für Rotation/Skalierung beinhalten. Nutzt eines unserer Objekte eine Rotscal-Animation, sucht das Spiel nach einer freien Gruppe und markiert diese dann als belegt. Selbes Problem wie bei GFX.
    • Palallozierung: Wenn wir über einen Paltag eine freie Palette suchen, wird diese freie Palette als besetzt markiert. Auch diese Markierung wird nicht durch clear_oam entfernt.

    Deswegen existiert noch eine weitere Funktion, die ALLE DREI Markierungen löscht und dannach automatisch clear_oam aufruft. Diese Routine nenne ich "despawn_oam" (FRD-Offset: 0x7784). Wenn ihr OAMs also spawnt, empfehle ich, sie über diese Funktion auch wieder zu despawnen.


    Wichtig: Das gilt sowohl für Rotscal- als auch für GFX-Animationen: Wenn die Dauer auf 0x0 gesetzt ist, dann wird automatisch auf die entsprechenden Werte gesetzt, nicht erhöht (so kann man seinen Frame 0 mit festen Werten definieren).

    6. Schlusswort:
    Ich weiß, dass sicherlich nicht viele damit etwas anfangen können. Jedoch ist es sicherlich auch für viele ganz interessant, wie simpel man im Grunde Animationen coden kann. Fragen bitte hier stellen.
    Wodka

    Wo war Gondor, als meine Klausurenphase begann?

    Edited 3 times, last by Wodka ().

  • Your documentation is nice, but for this one:

    Quote

    Ein Rotscal-Frame besteht aus 8 Bytes, die wie folgt strukturiert werden:

    Quellcode
    1
    [xscal (2 bytes)] [yscal (2 bytes)] [rotation (1 byte)] [duration (1 byte)]


    I can't understand the reason why it's in size of 8 bytes as 2+2+1+1=6. :)

  • A question (I use an English ROM)
    I've written a function to try to use the rotscale table:


    And the template data is:
    70 00 70 00 64 00 75 08 58 00 75 08 00 00 00 00 F0 03 75 08 0D 76 00 08 FF


    other things are not important, and the rotscale_table offset is 0x87503f0
    so:
    0x7503f0: 00 04 75 08
    0x750400: 00 01 00 01 0A 01 00 00 FF 7F 00 00 00 00 00 00


    I'm not sure about the reason why it doesn't work, and the obj created is only rotating and zooming out continuously.
    Enabling the double_size_flag in OAM structure won't solve this problem :(

  • Well I would guess, that the RAM Offset in a English ROM does not match the German one. Does an OAM at least appear on your screen?


    The other thing is your Rotscale script:
    Usually the game uses the first frame to declare the usual state of the OAM, e.g.:


    Code
    1. 00 01 00 01 00 00 00 00
    2. (0x100) (0x100) 0x0 0x0 0000


    Then, in the second frame, you would define your animation.


    The next thing is, that you did not create a loop nor did you define any frame who would case "backscaling". I will give you an example again:
    02 00 02 00 01 80 0000 | 00 02 00 02 80 00 0000 | FE FF FE FF FF 80 0000 | FE 7F 00 00 0000 0000
    First frame: (0x2) (0x2) (0x1) (0x80) = for 128 frames +0x2 scale in x,y and +0x1 rotation. In total we would reach +0x100 in scaling and 0x80 in rotation.


    3rd frame: Setting the standard reference rotscal values to the new ones (0x200 for scaling and 0x80 for rotation -> if you dont set them as reference the game will use the old settings as reference point.


    4th frame: (-0x2) (-0x2) (-0x1) (0x80) = for 128 frames the exact opposite of what we just did, to zoom back


    5th frame: 0x7FFE 0x0: Used to jump to frame 0 again.



    //Edit: Works for me at least (the script i wrote above).
    [Blocked Image: https://media.giphy.com/media/3o85xukaQXsuTMroIM/giphy.gif]

    Wo war Gondor, als meine Klausurenphase begann?

    Edited 2 times, last by Wodka ().

  • That's quite strange. I've tried this script:
    00 01 00 01 00 00 00 00 02 00 02 00 01 80 00 00 00 02 00 02 80 00 00 00 FE FF FE FF FF 80 00 00 FE 7F 00 00 00 00 00 00
    However the OBJ looks like this: (I've enabled the double_size_flag)
    [Blocked Image: http://i869.photobucket.com/albums/ab256/jiangzhengwenjz/1_zpszb08voiz.gif]
    Maybe there's something wrong with other things?


    I guess the error comes from the animation table, would you show me a correct one?
    My animation data is such:
    01 02 00 00 FE FF 00 00 (0x201 is tile number)

  • The same script works perfectly well for me. What oam do you use? Is there a callback that might change anything for the animation? And does your anim-table point to the first frame?

  • The same script works perfectly well for me. What oam do you use? Is there a callback that might change anything for the animation? And does your anim-table point to the first frame?


    I use a callback function located at 0xee4dc ( pointer: DD E4 0E 08 )
    In the template structure, the animation table pointer is F0 02 75 08
    0x7502F0: 00 03 75 08
    0x750300: 01 02 00 00 FE FF 00 00
    Would there be something wrong about the tags? I don't know what they really mean ?(

  • Nah, your GFX-Animation seems to be fine. What does your Rotscale-Table pointer look like?
    And Furthermore, what function is located at the callback's offset? Might be, that it changes something for animation, since at least for the first few frames the animation seems to be displayed correctly, but later fucks up.

  • Nah, your GFX-Animation seems to be fine. What does your Rotscale-Table pointer look like?
    And Furthermore, what function is located at the callback's offset? Might be, that it changes something for animation, since at least for the first few frames the animation seems to be displayed correctly, but later fucks up.


    I place them in the same format:
    pointer: F0 03 75 08
    0x7503F0: 00 04 75 08
    0x750400: 02 00 02 00 01 80 00 00 00 02 00 02 80 00 00 00 FE FF FE FF FF 80 00 00 FE 7F 00 00 00 00 00 00
    To make sure that the callback don't do anything, I change the pointer to 0D 76 00 08 and the "function" located at 0x760c is:

    Code
    1. bx lr


    As you can see, it returns immediately. But the problem is still there.

  • You do not point to your frame 0, do you?
    The Script has to start with the defintion of the first frame ( e.g. 00 01 00 01 00 00 00 00)


    Sorry for that, the script is now 00 01 00 01 00 00 00 00 02 00 02 00 01 80 00 00 00 02 00 02 80 00 00 00 FE FF FE FF FF 80 00 00 FE 7F 00 00 00 00 00 00
    But the problem is still there ;(

  • And what is the code you use to spawn the OAM? And why do you enable D-Size Flag in an extra code, you could just define the flag as set in the template. Would you mind positing the template and all the structures it points to?

  • And what is the code you use to spawn the OAM? And why do you enable D-Size Flag in an extra code, you could just define the flag as set in the template. Would you mind positing the template and all the structures it points to?


    Yes, you're right, but I think at least it won't cause any problem. :)
    Here's the structure:
    Template:
    02 00 01 00 64 00 75 08 F0 02 75 08 00 00 00 00 F0 03 75 08 0D 76 00 08
    0x750064: 00 00 00 C0 00 00 00 00
    0x7502F0: 00 03 75 08
    0x750300: 01 02 00 00 FE FF 00 00//0x201 = tile index
    0x7503F0: 00 04 75 08
    0x750400: 00 01 00 01 00 00 00 00 02 00 02 00 01 80 00 00 00 02 00 02 80 00 00 00 FE FF FE FF FF 80 00 00 FE 7F 00 00 00 00 00 00
    Then I use the source code to enable the rotscale_flag and double_size_flag as you can see above.

  • Nah, you have to enable Rotscale and D-Size Flag in your "final Sprite" (the 6 byte structure)


    It works!!!!!!!! Great thanks!!!!!!!!! :D
    [Blocked Image: http://i869.photobucket.com/albums/ab256/jiangzhengwenjz/1_zps6mk3zp44.gif]


    Another question is that can I use both an animation table & a rotscale table at the same time and what if I want an existing OBJ to animate/rotate/scale at some specific points?

  • Well, you can use both of them. Regarding the specified points that is a bit more complex. What the game does is simply using another animation.
    E.g. animation 0 is just an endless loop of a frame0 definition. Animation 1 would then be something else, and when the animation no. is changed, the animation is triggered.


    I am currently doing research on this (mostly if there are built in functions). However you have to trigger the new anmiatino via ASM it seems.

  • Well, you can use both of them. Regarding the specified points that is a bit more complex. What the game does is simply using another animation.
    E.g. animation 0 is just an endless loop of a frame0 definition. Animation 1 would then be something else, and when the animation no. is changed, the animation is triggered.


    I am currently doing research on this (mostly if there are built in functions). However you have to trigger the new anmiatino via ASM it seems.


    Are you speaking of the case that the tag is set to 0xFFFF? ?( (case2 in your tut)

  • No. In the oam structure there is a byte that toogles the index in the animation table that is used. Via asm you have to change this index. However there seem to be kind of built in functions.