Actor

From Boktai Hacking Wiki
Revision as of 17:44, 19 September 2024 by Raphi (talk | contribs)

The Boktai games use an actor system to keep track of all "objects" currently existing in the game. Every actor has a callback that will be called every frame. Examples of actors are: Django, the camera, enemies...

Structure

Actors are defined using a pattern similar to object-oriented programming. There is a "base class", Actor, and "subclasses", like DjangoActor for example. Each subclass contains data specific to that actor type (for example, Django's actor would store his position, his stats, his sprite, etc., while the camera actor would store the camera position). In practice, this looks like this:

// Called every frame
typedef void (*FrameCallback)(Actor* actor);

// Return -1 to skip deletion for this frame
typedef int (*DestroyCallback)(Actor* actor);

// Base class, this struct must be the 1st field of every Actor subclass
struct Actor {
    Actor* linkPrev;           // Pointer to previous actor (linked list, nullable)
    Actor* linkNext;           // Pointer to next actor (linked list, nullable)
    FrameCallback onFrame;     // function pointer, if set: called every frame by the game's main loop
    DestroyCallback onDestroy; // function pointer, if set: called when the actor is about to be deleted
    u16 unknown_0x10;
    u16 flags;   // Set to 1 to schedule this actor for deletion in the next frame
    u8 priority; // Priority, from 0 to 13 (inclusive)
};

// Example subclass
struct ExampleActor {
    Actor actor; // Must be the 1st field
    int foo;     // Whatever actor specific data
    int bar;
    int baz;
};

Actor lists

For each of the 14 actor priorities, there is a separate doubly-linked list containing the actors of that priority. Each priority can be enabled/disabled separately. This is used to e.g. disable enemy actors while cutscenes are playing:

struct ActorList {
    // Pointer to 1st actor of that priority, nullable
    Actor* head;

    // If (disableFlags & g_ActorDisableFlags) != 0, then these actors will be skipped.
    // Actors will not be deleted in this state, and no onFrame/onDestroy callbacks will be executed.
    u32 disableFlags;
};

// Stored in IWRAM, see each game's RAM map page
ActorList[14] g_ActorLists;
u32 g_ActorDisableFlags;

Actor functions

Each game has these functions to deal with actors in general, see each game's ROM map page for their locations:

  • void Actor_RunAll(): Called by main() every frame. Calls onFrame/onDestroy callbacks (starting with priority 0), and free()s destroyed actors.
  • Actor* Actor_Create(u8 priority, uint size): malloc()s an actor and adds to g_ActorLists.
  • void Actor_SetCallbacks(Actor* actor, FrameCallback onFrame, DestroyCallback onDestroy): Just sets the onFrame/onDestroy fields
  • void Actor_Install(Actor* actor): Adds an actor to g_ActorLists (automatically called by Actor_Create).
  • void Actor_Uninstall(Actor* actor): Removes an actor from g_ActorLists (automatically called by Actor_RunAll).

Each actor type will have a "constructor" function, which calls Actor_Create(), followed by Actor_SetCallbacks(), followed by an actor-specific initialization function.

Actor priorities

Priority Description
0 System / TODO
1
2
3
4
5
6 Protagonist
7 Camera
8
9
10
11
12
13

See also