Actor: Difference between revisions

From Boktai Hacking Wiki
No edit summary
No edit summary
 
(3 intermediate revisions by the same user not shown)
Line 3: Line 3:
= Structure =
= Structure =


Actors are defined using a pattern similar to object-oriented programming. There is a "base class", <code>Actor</code>, and "subclasses", like <code>DjangoActor</code> 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 would store the camera position). In practice, this looks like this:
Actors are defined using a pattern similar to object-oriented programming. There is a "base class", <code>Actor</code>, and "subclasses", like <code>DjangoActor</code> 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:


<syntaxhighlight lang="c">
<syntaxhighlight lang="c">
Line 20: Line 20:
     u16 unknown_0x10;
     u16 unknown_0x10;
     u16 flags;  // Set to 1 to schedule this actor for deletion in the next frame
     u16 flags;  // Set to 1 to schedule this actor for deletion in the next frame
     u8 priority; // Priority or type, from 0 to 13 (inclusive)
     u8 priority; // Priority, from 0 to 13 (inclusive)
};
};


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


* <code>void Actor_RunAll()</code>: Called by main() every frame. Calls onFrame/onDestroy callbacks, and free()s destroyed actors.
* <code>void Actor_RunAll()</code>: Called by main() every frame. Calls onFrame/onDestroy callbacks (starting with priority 0), and free()s destroyed actors.
* <code>Actor* Actor_Create(u8 type, uint size)</code>: malloc()s an actor and adds to g_ActorLists.
* <code>Actor* Actor_Create(u8 priority, uint size)</code>: malloc()s an actor and adds to g_ActorLists.
* <code>void Actor_SetCallbacks(Actor* actor, FrameCallback onFrame, DestroyCallback onDestroy)</code>: Just sets the onFrame/onDestroy fields
* <code>void Actor_SetCallbacks(Actor* actor, FrameCallback onFrame, DestroyCallback onDestroy)</code>: Just sets the onFrame/onDestroy fields
* <code>void Actor_Destroy(Actor* actor)</code>: Schedules an actor for deletion during the next frame (sets actor->flags |= 1). The next Actor_RunAll() will call the onDestroy callback, and then call Actor_Uninstall() followed by free().
* <code>void Actor_Install(Actor* actor)</code>: Adds an actor to g_ActorLists (automatically called by Actor_Create).
* <code>void Actor_Install(Actor* actor)</code>: Adds an actor to g_ActorLists (automatically called by Actor_Create).
* <code>void Actor_Uninstall(Actor* actor)</code>: Removes an actor from g_ActorLists (automatically called by Actor_RunAll).
* <code>void Actor_Uninstall(Actor* actor)</code>: Removes an actor from g_ActorLists (automatically called by Actor_RunAll).
Line 63: Line 64:
Each actor type will have a "constructor" function, which calls Actor_Create(), followed by Actor_SetCallbacks(), followed by an actor-specific initialization function.
Each actor type will have a "constructor" function, which calls Actor_Create(), followed by Actor_SetCallbacks(), followed by an actor-specific initialization function.


= Actor types =
= Actor priorities =


{| class="wikitable exportable"
{| class="wikitable exportable"
! Type || Description
! Priority || Description
|-
|-
| 0 || System / TODO
| 0 || System / TODO
Line 78: Line 79:
| 4 ||
| 4 ||
|-
|-
| 5 ||
| 5 || Timers
|-
|-
| 6 || Protagonist
| 6 || Protagonist

Latest revision as of 12:57, 21 September 2024

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_Destroy(Actor* actor): Schedules an actor for deletion during the next frame (sets actor->flags |= 1). The next Actor_RunAll() will call the onDestroy callback, and then call Actor_Uninstall() followed by free().
  • 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 Timers
6 Protagonist
7 Camera
8
9
10
11
12
13

See also