Skip to content

Commit

Permalink
Add more docs (#547)
Browse files Browse the repository at this point in the history
* Add more docs
  • Loading branch information
MegaMech authored Jan 16, 2024
1 parent 22c5c4e commit 05ce12b
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 7 deletions.
38 changes: 37 additions & 1 deletion docs/basics/actors.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,38 @@
\page actors How Actors Work
# Actors
# Actors
If you are familiar with oot or sm64 prepare to be very disappointed. Both games split actors into separate files. In an unorderly fashion, mk64 appears to place all actors in the same file save for the odd exception.

Actor setup:
```c
// Loop through the actor list and run that particular actors behaviour.
for actorListSize {
actor = gActorList[i]
switch(actor->type) {
case ACTOR1:
actor_name(args, actor);
break;
case ACTOR2:
another_actor(args, actor);
break;
}
}

// Camera/Mat4 are optional
void actor_name(Camera, Mat4, actor) {
actor->pos[x] += 10; // Increase the actors X position by ten every frame or game loop.
actor->rot[y] -= 1; // Decrease the actors Y rotation by one every frame or game loop.

// Increase the actors velocity until it reaches fifteen.
if (actor->velocity[z] < 15) {
actor->velocity[z] += 5 // Increase the actors Z velocity by five every frame.
}
}
```
Check actor_types.h for a full list of options. You can create a new actor struct for your actor and customize it or use a predefined one. All actor structs must retain the same size. Generally, the types in the struct may be modified so long as `type` and `flags` stay the same as those are used elsewhere.
See `update_obj_railroad_crossing` for an example of how a timer may be setup and used.
Audio may be activated in the following method:
`func_800C98B8(actor->pos, actor->velocity, s32_audio_flag);`
For more complex uses such as distanceFrom and collision, you will need to analyze the other actors.
33 changes: 31 additions & 2 deletions docs/basics/actorsmenu.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
\page actorsmenu Actors

\htmlonly
Actors are dynamic game objects usually subject to game physics such as gravity, force, and collision. They might move around the map, spin, or interactive in some manner. Alternatively, static game objects cannot move and cannot be interacted with. They can use collision but not physics. A course model and Mario Raceway's Pipe are examples of static objects. Any of the items or player karts are examples of dynamic game objects; actors.

How actors in mk64 works. There are two kinds of actors.
mk64 contains two systems for implementing actors. They have been deemed as actors and objects, albeit an explicit or categorical difference between the two has yet to be determined. The running theory is that the systems were designed by different developers that were perhaps not communicating resulting in game objects being randomly distributed between the two.

The two main variables to concern yourself with are `gActorList` and `gObjectList`; the core containers of the two systems.

`gActorList` contains:
```
trees, bushes, falling rocks, kiwano-fruit, banana, shells, piranha-plant, train wheels, rail-road crossing, cows, yoshi-valley's egg, spinning signs, palm trees, paddle for the paddle-wheeled boat, wheels for cars/trucks, etc.
```
The actor code has two main parts; the update code and the render code. The update code alters the position/rotation of the object whereas the render code displays the object on the screen.

`gObjectList` contains:
```
thwomps, bowser fire-breath, moles, hedgehogs, snowmen, crabs, etc (also, probably penguins and birds).
```
The object system is much more complex than actors and is not well documented.

<style>
.pagebutton {
Expand Down Expand Up @@ -98,7 +113,21 @@ p {
</a>
</div>

<div class="pagebutton">
<a class="pagea" href="objects.html">
<div class="pagelink">
<div class="pageimg"><img width=320 src="buttonimage.png" /></div>
<div class="content">
<div class="pageheading">Objects</div>
<div class="pagedescription">
<p>Some object stuff</p>
</div>
</div>
</div>
</a>
</div>

\endhtmlonly

\subpage actors

\subpage objects
8 changes: 4 additions & 4 deletions docs/basics/basicsmenu.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,13 @@ p {
</div>

<div class="pagebutton">
<a class="pagea" href="test.html">
<a class="pagea" href="controlflow.html">
<div class="pagelink">
<div class="pageimg"><img width=320 src="buttonimage.png" /></div>
<div class="content">
<div class="pageheading">test</div>
<div class="pageheading">Control Flow</div>
<div class="pagedescription">
<p>test</p>
<p>Introduction to mk64's operating states and threading. Acclimate to the codebase with this essential read.</p>
</div>
</div>
</div>
Expand Down Expand Up @@ -147,6 +147,6 @@ p {

\subpage compiling
\subpage concepts
\subpage test
\subpage controlflow
\subpage terminology
\subpage buildwindows
57 changes: 57 additions & 0 deletions docs/basics/controlflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
\page controlflow Control Flow

# Introduction to State
The developers wrote mk64 using a state-driven paradigm. This manifests itself in a variety of ways but as a quick example lets discuss the following variables. `gGamestate`, `gGameMode`, and `gCurrentCourseId`. Code for menus, racing, and credits must be modularized in some fashion. The gamestate variable contains the current state and during runtime branches into the relevant code while skipping code not pertaining to the current state. The racing code does not run while the user operates the menu. Let's inspect a simple example of a state-driven mechanism:
```c
switch(gCurrentCourseId) {
case YOSHI_VALLEY:
load_and_render_yoshi_egg();
break;
case MARIO_RACEWAY:
load_and_render_pipe();
break;
}
```
This code loads resources based on a specific course. An entire spaghetti tree of code may be imagined based on many series of conditional statements.

# Threading
The game begins by setting up its four threads; idle, video, audio, and the game loop.
The idle thread allows the cpu to sleep. Without it, if at any time execution of all threads were paused, the cpu would never be able to continue. The idle thread is active if all the other threads are paused.

As such, the idle thread runs the following loop: `while(TRUE);` (it runs in a perpetual loop of nothing; sleep). In mips assembly it looks like this:
```
.L800005B8:
b .L800005B8
nop
```
b stands for branch which acts akin to a goto. In this case, branch to the label `.L800005B8`. This creates an infinite loop. Whenever the cpu branches it always runs the next instruction as well which is called a delay slot. This means the cpu will continuously branch then run `nop` or `no operation` with no method of escaping the loop (except for when another thread has a higher priority which means the cpu switches to that thread and stops running the idle thread).

N64 threads are ran based on priority running whichever thread holds the most of it. Threads can also pause and wait for events. Note that the N64 is not multi-threaded by modern standards as the other threads contain specific purposes which slightly differs from the concept of splitting a single program into multiple processes for efficiency.

# Overall Control Flow
```
init_threads:
idle, video, audio, gameloop
gameloop:
audio
jumpTo a specific menu or race based on a gameState flag.
profiler
config_gfx_pool
read_controllers
game_state_controller
endDL/vsync
game_state_controller:
switch(loc)
menus -> switch(menu) { // do menu stuff }
race_logic_loop -> spaghetti
podium_ceremony
credits
video:
handles interaction between video/audio threads.
handles vblanking and some elements pertaining to framebuffer
most of all, handles which step of rendering a frame the cpu is in.
Checks when new to start new sp tasks
```
If mk64 is in a menu state it will branch off to the menu code, running relevant bits of code based on more flags such as which particular menu the user is in. This will loop until the state changes to a different one such as race mode. If mk64 is in a race state, then race related code is ran and it spaghetti's off into a wide series of branches. This may include concepts such as `isLinedUp, isRacing, isRaceFinished, gotoNextCourse, isHuman, and isAI`.

This relatively primitive design could be defined as a state machine from an abstract point of view. This would differ from an OOP design that uses objects and hierarchy. You will become very familiar with this design principle as you explore the code-base. During any step of the game loop, a switch can be setup to check a flag then run code relevant to the situation. For instance, a flag can check whether a race is in-progress or complete. If in-progress set the player to human controlled. If complete, set player to AI controlled.
2 changes: 2 additions & 0 deletions docs/basics/objects.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
\page objects
# Objects

0 comments on commit 05ce12b

Please sign in to comment.