Recreation engine documentation · zladx/LADX-Disassembly Wiki · GitHub
Overview
This web page describes the high-level workings of Hyperlink’s Awakening sport engine. It explains how the engine is structured, how the assorted subsystems are made, and the way the programming selections influence the sport design itself.
(N.B.: for low-level particulars or hacking notes, use extra detailed documentations, just like the Maps data format documentation.)
Abstract
1. High-level structure
Rendering on the Recreation Boy isn’t easy. It has no double-buffering, and the PPU (the graphics processor) can solely be accessed through the quick period of time between two frames: the V-blank interval.
So the usual rendering setup is to pre-compute every body whereas the earlier one is being drawn by the PPU – after which, when the quick V-blank interval happens, to repeat all pre-computed assets and values to the now-unlocked VRAM on the PPU.
That is why Hyperlink’s Awakening engine has two predominant methods that carry out these duties: the Render loop and the V-blank interrupt handler.
The render loop
The primary render loop is the piece of code chargeable for dealing with all the sport logic. It runs whereas the PPU is rendering a body (which that entry to VRAM is locked). It’s chargeable for:
- Studying joypad inputs,
- Executing the gameplay code,
- Configuring the audio output,
- Configuring the rendering of particular results utilizing H-blank manipulation.
The primary render loop also can add giant chunks of graphics to VRAM, by briefly disabling the LCD display screen (see the “Graphics” part under).
On the finish of the loop, it waits for V-Clean, then begins rendering a brand new body.
See https://kemenaran.winosx.com/posts/links-awakening-render-loop/
The V-blank interrupt handler
The V-blank interrupt handler is a smaller piece of code, known as by the CPU as quickly because the PPU enters the V-blank interval. Throughout this quick time, it will probably:
- Copy a small quantity of tiles to VRAM,
- Replace animated tiles,
- Replace the tiles representing Hyperlink’s sprite (relying on its animation state),
- Copy the palettes buffer to VRAM,
- Copy the sprites attributes buffer to the OAM reminiscence in VRAM.
It is usually chargeable for dealing with some animations through the pictures cutscenes.
2. Graphics
As we noticed above, graphics can solely be uploaded to VRAM through the V-blank interval, or whereas the LCD display screen is off. That is why the gameplay code by no means copy graphics on to VRAM: it as an alternative units flags to inform the engine which graphics must be uploaded on the subsequent iteration of the render loop.
Hyperlink’s Awakening engine offers a couple of totally different services for this.
The gameplay code can set flag to request these assets to be loaded through the V-blank interval between two frames:
- Importing a brand new objects tilesheet,
- Importing a brand new entity spritesheet,
- Importing coloration palettes (CGB solely).
However some graphics assets are fairly giant, and importing them solely utilizing the few cycles obtainable through the V-blank interval would take a variety of frames.
That is why the gameplay code also can request graphic assets to be loaded abruptly, whereas the rendering is disabled. For this, the LCD display screen is shut down (which shows a white display screen, and unlocks VRAM), then graphics will be copied to VRAM utilizing an arbitrary period of time. On the finish of the copy, the display screen is enabled once more. This leads to a white display screen being displayed through the add, however it’s a lot quicker than utilizing the V-blank time interval alone.
This system can be utilized by the gameplay code to:
- Add a big tileset,
- Add a big tilemap (and, on GBC, the related tilemap attributes).
2.1 Updating Objects tilesheets (throughout V-blank)
Rooms are displayed by composing two high-level primitives: objects and entities. The objects are the static 16×16 blocks that compose the room construction; they’re displayed utilizing the Recreation Boy Background map. Entities are the dynamic actors of the room (NPCs, enemies, and so forth); they’re displayed utilizing sprites.
Objects within the overworld rooms are rendered utilizing two forms of tiles:
- A standard set of overworld tiles shared between all overworld rooms;
- A set of tiles particular to the present part on the overworld.
So throughout a transition from a room to a different, the gameplay code can to request the tilesheet for the brand new room to be loaded through the subsequent V-blank interval.
Overworld rooms are grouped in 2×2 sections (i.e. 4 rooms). Every part has a tileset ID. When a room is transitioned to, earlier than beginning the transition, the sport checks if the tileset of the brand new room is totally different from the present one, and if that’s the case write to hNeedsUpdatingBGTiles
to request the 32 particular tiles for this part to be uploaded to VRAM through the subsequent V-blank interval.
To keep away from glitches through the transition, there’s a particular “Hold Present” tileset, which instructs the engine to not change the tileset, whichever it’s. The world map is constructed in order that more often than not, the participant all the time walks by way of a “Hold Present” part between two totally different sections, which avoids transition glitches. See “The hidden structure of Link’s Awakening Overworld map”
2.2 Updating entity spritesheets (throughout V-blank)
Entities are the dynamic actors within the sport, normally displayed utilizing sprites.
At a given second, 4 spritesheets of 16 tiles every are reserved for entity sprites. The gameplay code can write to hNeedsUpdatingEntityTilesA
or hNeedsUpdatingEntityTilesB
to request a spritesheet to be loaded.
Throughout the next V-Clean durations, when the VRAM is unlocked, the interrupt code reads that request, and copies 4 tiles from the spritesheet to the requested location. Solely 4 tiles are copied as a result of the V-Clean interval is kind of quick; which suggests loading a complete spritesheet spans throughout a number of frames.
2.3 Importing a coloration palette (throughout V-blank)
TODO: doc utilization of wBGPal1
2.4 Importing a big tileset (display screen off)
TODO: doc utilization of wTilesetToLoad
2.5 Importing a big tilemap and tilemap attributes (display screen off)
TODO: doc utilization of wBGMapToLoad
2.6 Animated tiles
TODO
3. Rooms
The primary gameplay takes place in non-scrollable screen-wide rooms. These rooms will be outside (on the Overworld) or indoor (inside homes, dungeons, and so forth.)
Room teams
The sport rooms are break up into 3 room teams, of 256 rooms every (plus a particular group):
- Rooms group 1: incorporates all of the 256 Overworld rooms;
- Rooms group 2: incorporates rooms for dungeons 1 to six, plus some caves;
- Rooms group 3: incorporates rooms for dungeons 7 and eight, and the remaining of caves, homes, and so forth.;
- Particular group: incorporates rooms for the colour dungeon.
So a particular room will be recognized utilizing its room group (1-3) and its room id on this group (0-256).
The three room teams, and their respective rooms. The Coloration Dungeon particular group isn’t represented right here. Credit: Saver
Maps and layouts
TODO: maps
On the Overworld, rooms are saved as they’re laid out through the sport, on a 16×16 grid of rooms.
However indoors, for house effectivity, rooms are usually not saved repeatedly. As an illustration, when shifting by way of the fitting door of a dungeon room (e.g. room 0x34), the brand new room might be not the subsequent room within the rooms group (that may be room 0x35).
To know which rooms are North, South, East and West of a given room, the sport makes use of layouts. These appear to be the dungeons maps, however retailer the ids of every of the dungeons room as they’re organized geographically.
The map format for the primary dungeon.
Room construction
A room is outlined by:
- The ground object it makes use of;
- The animated tiles it makes use of;
- An inventory of static objects within the room (partitions, bushes, and so forth);
- The dynamic entities within the room (NPCs, enemies, and so forth.).
To load a given room, the sport constructs an in-memory map of the room objects. For this, the sport:
- Reads the room ground object, and fill the entire objects map with it;
- For every object within the objects listing:
- Learn the article command (which object, the place, spanning what number of slots, vertical or horizontal);
- Write the objects to the map.
3.1 Displaying a room straight
After deciding on a save file, when getting into a door, or when warping to a brand new location, the sport hundreds a brand new room in a single go.
The Overworld gameplay handler is chargeable for this: it will probably load a room’s knowledge abruptly.
Nevertheless this takes far more time than a single body. To keep away from blocking the primary loop for a very long time, which might stop the engine from processing audio, occasions, and so forth., the loading is break up into a number of loading levels. When a room is loaded, the Overworld gameplay handler will execute one in all these levels, then mark the stage as accomplished and return to the primary loop. The following iteration of the loop will then dispatch to the subsequent loading stage. Every stage ought to then take no extra time than a body.
The loading levels are:
- Decode the room object map to reminiscence, and instanciate the room entities.
- Lookup the room tileset to make use of, and request it to be copied to the VRAM. _(The copy will probably be requested utilizing
hTilesetToLoad
, which can shut the console display screen off to unlock VRAM and carry out the copy quicker).
As soon as all of the levels are accomplished, it then transition to the 8 stage, which is the interactive gameplay.
3.2 Transitioning between rooms
Transitioning easily between rooms, utilizing the interpretation animation seen within the sport, is kind of extra complicated.
That is for 2 causes:
- Because the transition is steady, the gale should render repeatedly: it will probably’t shut the display screen off to repeat new knowledge quicker.
- Throughout the transition, each the previous and new room will probably be seen. So graphics for each rooms have to be obtainable on the similar time.
To do that, the sport will carry out roughly the identical steps, however with particular care to maintain all of them inside the body funds.
TODO: steady loading steps
4. Entities
Entities are the dynamic actors current throughout the primary gameplay (NPCs, enemies, and so forth); they’re displayed utilizing sprites.
4.1 Loading entity graphics
Entities are displayed on display screen utilizing sprites. On the Recreation Boy, sprites will be both a single tile (8×8 px) or two tiles stacked vertically (8×16 px). And normally, entities are composed of a number of sprites stitched collectively.
So for an entity to be displayed on-screen, its tiles must be copied to VRAM, after which the tiles indices have to be referenced correctly (normally relying on the entity place: dealing with frontward, backwards, left or proper).
As we noticed above, at any level in the primary gameplay, there are 4 slots obtainable in VRAM, equivalent to 4 entity spritesheets. Every spritesheet has 16 tiles. A spritesheet might comprise tiles for a single entity (like a Moblin), for a number of entities (like Keeses and Beetles, each on the identical spritesheet), or for less than a part of an entity (just like the Bottle Grotto genie, which makes use of 2 spritesheets, or the Angler Fish, which makes use of all 4).
Every room defines which spritesheets must be loaded for its entities to be displayed. For this, every room defines 4 related spritesheet-ids. When transitioning from a room to a different, the sport engine compares the spritesheets presently loaded in VRAM with the spritesheets requested by the brand new room, and marks the non-loaded-yet ones as needing to be copied to VRAM (see 2.2 Updating entity spritesheets (during V-blank)).
The fours spritesheets for room 07 on the Overworld.
Variety of spritesheets obtainable
Throughout a scrolling transition from one room to a different, the spritesheets for each the previous and the brand new rooms must be obtainable (in any other case entities from the previous room would look corrupted through the transition). So a room can solely load two new spritesheets: the opposite twos, utilized by the entities of the earlier room, want to stay obtainable.
This limitation does not apply when warping on to a brand new room, and not using a scrolling transition (for example when shifting by way of stairs, or from the overworld to indoor rooms). In that case, all 4 spritesheets are loaded directly. Some giant entities are particularly positioned in rooms accessible solely by warps, in order that they’ll use all 4 spritesheets (for example Evil Eagle or Manbo the Sunfish).
Additionally, on the overworld, the primary spritesheet is all the time overwritten with the sprites of the NPC following the participant (Bow-Wow, Marin, ghost, and so forth.). Inside dungeons and homes, though, the primary spritesheet can be utilized to show further enemies.
Mapping an entity to tiles
Apparently, there is no dynamic allocation of sprite slots. For a given room, the spritesheets will all the time be loaded in the identical slots. Many of the entities require a particular slot for use: for example, Octorocks are anticipated to have their spritesheet loaded in slot 2, in addition to Moblins. Which additionally implies that Octorocks and Moblin can’t be displayed in the identical room (as a result of they each count on the identical spritesheet for use).
(Some entities use totally different spriteslots relying on the room they’re in, however that is an exception.)
Which means the entity-to-sprite mapping is an easy array of tiles indices, hard-coded relying on the anticipated spriteslot.
As an illustration, to illustrate the tiles for a front-facing Moblin are the tiles n° 2, 3, 4 and 5 in its spritesheet. We’re utilizing 8x16px tiles, so referencing tiles 2 and 4 will probably be sufficient. As rooms load the Moblin spritesheet in slot 2, for our two sprites to reference these tiles, we’ll write one thing like:
MoblinFrontFacingSprites:
db ($20 x 2) + 2
db ($20 x 2) + 4
Coloration dungeon particular circumstances
TODO
5. Audio
TODO
6. Coloration conversion
TODO
Coloring room objects require two further items of information: tile attributes and coloration palettes.
6.1 Coloring Background objects
A tile attribute defines which palette is utilized to this tile. As an object is 2×2 tiles, every object wants 4 tile attributes.
Not like the object-to-tilemap mapping, which is similar for all rooms of a map group, the object-to-tile-attributes mapping is room-specific. This enables the sport engine to, for example, coloration the rocks of a sure room utilizing the BG0
palette – however in one other room, to make use of the BG2
palette for those self same rocks.
To make use of much less house, object-to-tile-attributes mappings are factored into teams, which can be utilized by a number of totally different rooms. That implies that discovering the correct tile attributes for an object is completed with the next steps:
- Get the map group and room id,
- Discover the pointer to the tile attributes mapping,
- Get the article id,
- Discover the tile attributes (4 bytes) within the mapping for this object id,
- Copy the tile attributes to the BG VRAM.
6.2 Coloring sprites
6.3 Loading palettes
Which palette is used for a room is outlined by an index at 21:42EF
(one byte per room) which is then used to index an desk at 21:402B
to get the pointer to the precise palette in financial institution $21
.