Files
dusk/.claude/rpg/world.md
T
2026-06-18 14:59:21 -05:00

4.2 KiB
Raw Blame History

World

Source: src/dusk/rpg/overworld/


Coordinate system

Three nested coordinate spaces, each defined in worldpos.h:

Type Description Unit
worldpos_t Tile-level absolute position {x, y, z} worldunit_t (int16)
chunkpos_t Chunk-grid position {x, y, z} chunkunit_t (int16)
fixed_t[3] Smooth sub-tile position used by entities Q24.8 fixed-point

One chunk = CHUNK_WIDTH × CHUNK_HEIGHT × CHUNK_DEPTH tiles (16 × 16 × 8). The loaded world window = MAP_CHUNK_WIDTH × MAP_CHUNK_HEIGHT × MAP_CHUNK_DEPTH chunks (5 × 5 × 3).

Conversion helpers (all in worldpos.c):

worldPosToChunkPos(&worldPos, &chunkPos);   // tile → chunk grid
chunkPosToWorldPos(&chunkPos, &worldPos);   // chunk grid → tile origin
worldPosToChunkTileIndex(&worldPos);        // tile → index within its chunk
chunkPosToIndex(&chunkPos);                 // chunk grid → linear index in MAP.chunks[]
worldPosToFixed(&worldPos, fixedOut);       // tile → entity fixed position
fixedToWorldPos(fixedPos);                  // entity fixed → tile (truncates frac)

Tiles

Defined in tile.h as a plain tile_t enum:

TILE_SHAPE_NULL    — empty / unloaded
TILE_SHAPE_GROUND  — solid flat tile
TILE_SHAPE_RAMP_*  — directional ramps (N/S/E/W + diagonals NE/NW/SE/SW)

Key predicates:

  • tileIsWalkable(tile) — true for GROUND and all ramp shapes.
  • tileIsRamp(tile) — true only for ramp shapes.

Entity walk code (entity.c) checks both the current tile and the target tile to decide whether the entity steps forward flat, raises one Z level (walking up a ramp), or falls one Z level (stepping onto a downward ramp from above).


Chunks

chunk_t (chunk.h) holds:

  • position — its chunkpos_t in the world grid
  • tiles[CHUNK_TILE_COUNT] — flat array of tile_t, indexed by chunkGetTileIndex()
  • vertices[CHUNK_VERTEX_COUNT] / mesh — pre-baked mesh uploaded to GPU on load
  • entities[CHUNK_ENTITY_COUNT_MAX] — indices into ENTITIES[] currently in this chunk (sentinel 0xFF)
  • testColor — temporary debug color (checkerboard), will be replaced by real tileset data

Tile layout within a chunk is z * W*H + y * W + x (Z-major, row-major in XY).


Map

map_t MAP (map.h) is the single global map instance.

chunk_t chunks[MAP_CHUNK_COUNT];         // flat storage — index is NOT world position
chunk_t *chunkOrder[MAP_CHUNK_COUNT];    // draw-order sorted pointers into chunks[]
chunkpos_t chunkPosition;               // world-grid origin of the loaded window
bool_t loaded;

Load / unload

mapInit() allocates chunk meshes and performs the initial load of all chunks in the starting window.

mapPositionSet(newPos) shifts the window:

  1. Determines which of the MAP_CHUNK_COUNT slots remain within the new window vs. fall outside it.
  2. Calls mapChunkUnload() on every chunk that falls outside (nulls its entity slots, zeroes vertCount).
  3. Reuses freed slots for newly-in-range chunks; calls mapChunkLoad() on each.
  4. Rebuilds chunkOrder[] in XYZ order for the new position.

Chunk load (current stub)

mapChunkLoad() currently:

  • Fills all tiles with TILE_SHAPE_GROUND
  • Assigns a checkerboard debug color based on chunk XY parity
  • Bakes a flat sprite-batch quad mesh for the z=0 layer and uploads it via meshFlush()
  • Skips mesh generation for z > 0 chunks (they're empty)

Tile lookup

tile_t mapGetTile(const worldpos_t position);

Converts position to its chunk, looks up the chunk in chunkOrder, then indexes into chunk->tiles[]. Returns TILE_SHAPE_NULL for any out-of-bounds position or when the map is not loaded.


Camera

rpgcamera_t RPG_CAMERA (rpgcamera.h) has two modes:

RPG_CAMERA_MODE_FREE            // free worldpos; camera.free holds the position
RPG_CAMERA_MODE_FOLLOW_ENTITY   // tracks ENTITIES[followEntityId]

rpgCameraGetPosition() returns the active world tile position in either mode.

The scene renderer (sceneoverworld.c) uses rpgCameraGetPosition() to build the glm_lookat view matrix. When following an entity, it sub-tile interpolates between entity->lastPosition and entity->position using entity->animTime / ENTITY_ANIM_WALK_DURATION to smooth movement.