Main game scene: seeded terrain grid, camera rig, environment #10

Merged
liamjd merged 3 commits from 6-main-game-scene-grid into main 2026-08-15 15:57:53 +01:00
Owner

Stands up res://scenes/game.tscn: a seeded terrain grid under an orthographic camera, lit and framed, with four shape presets. No pawns, no building, no UI — this proves the basics work and is the consumer the seed pipeline (#1, #2, #3) was built for.

What landed

TerrainTerrainGrid (GridMap) with heights quantised into integer levels, a MeshLibrary generated at runtime, full-depth tile columns and a top-only collider. Carried over from the OrthographicGame POC along with the noise normalisation pass, which is load-bearing: fractal Perlin never reaches its nominal range, so sampling straight into height_scale gives a near-flat map.

Shape presetsTerrainPreset resources for plains, island, crater and canyon. Shaping happens in normalised −1..1 space before scaling to world units, so shape parameters stay independent of height_scale; the POC applied falloff after scaling, which entangled the two. The canyon's centre line meanders via a separate noise generator so it does not read as a dug trench.

The POC's falloff_start = 0.80 was not carried over as a tuned value — it was fitted to guarantee reachable pawn spawns, and with no pawns that constraint does not apply.

Camera — POC rig: yaw on the rig, pitch on the camera, zoom changes Camera3D.size rather than boom length. game.gd centres it on load; it previously defaulted to the map's corner.

Lighting — sky-sourced ambient so shadowed geometry stays readable, which the canyon floor needed badly.

Seed threading

TerrainGrid does not read GameState. game.gd passes GameState.run_seed in, keeping the generator testable in isolation and stopping the autoload becoming an implicit dependency of every system that later wants determinism.

This forced an ordering change: TerrainGrid._ready() no longer calls generate(), because child _ready() runs before the parent's and it would otherwise build a map before the seed arrived. Both sides carry a comment — "why doesn't this node generate itself?" is exactly the question someone answers by putting generate() back.

randomize_seed was removed as a second, competing source of randomness; GameState already randomises on startup.

Verification

Seed reaches the generator:

GameState.run_seed=3017397413  map.map_seed=3017397413  match=true
GameState.run_seed=3743863618  map.map_seed=3743863618  match=true
GameState.run_seed=1774896844  map.map_seed=1774896844  match=true

Same seed reproduces, different seed differs:

seed=777 -> 1037 walkable (969 on main landmass)
seed=777 -> 1037 walkable (969 on main landmass)
seed=778 -> 1492 walkable (879 on main landmass)

All four presets verified visually with headed captures — gl_compatibility renders nothing headless, so a clean headless run proves nothing about the picture.

Deliberately deferred

  • #7 — palette lives in terrain_grid.gd as Earth-toned constants, and kind is picked by elevation alone, which makes the crater's floor and exterior share a colour
  • #8 — the R/T debug keys are not gated out of release builds
  • #9 — sky and ambient are scene constants, not per-location

Pathfinding (AStar2D) came across with the POC code but has no consumer until pawns exist.

Closes #6

Stands up `res://scenes/game.tscn`: a seeded terrain grid under an orthographic camera, lit and framed, with four shape presets. No pawns, no building, no UI — this proves the basics work and is the consumer the seed pipeline (#1, #2, #3) was built for. ## What landed **Terrain** — `TerrainGrid` (`GridMap`) with heights quantised into integer levels, a `MeshLibrary` generated at runtime, full-depth tile columns and a top-only collider. Carried over from the `OrthographicGame` POC along with the noise normalisation pass, which is load-bearing: fractal Perlin never reaches its nominal range, so sampling straight into `height_scale` gives a near-flat map. **Shape presets** — `TerrainPreset` resources for plains, island, crater and canyon. Shaping happens in normalised −1..1 space *before* scaling to world units, so shape parameters stay independent of `height_scale`; the POC applied falloff after scaling, which entangled the two. The canyon's centre line meanders via a separate noise generator so it does not read as a dug trench. The POC's `falloff_start = 0.80` was **not** carried over as a tuned value — it was fitted to guarantee reachable pawn spawns, and with no pawns that constraint does not apply. **Camera** — POC rig: yaw on the rig, pitch on the camera, zoom changes `Camera3D.size` rather than boom length. `game.gd` centres it on load; it previously defaulted to the map's corner. **Lighting** — sky-sourced ambient so shadowed geometry stays readable, which the canyon floor needed badly. ## Seed threading `TerrainGrid` does not read `GameState`. `game.gd` passes `GameState.run_seed` in, keeping the generator testable in isolation and stopping the autoload becoming an implicit dependency of every system that later wants determinism. This forced an ordering change: `TerrainGrid._ready()` no longer calls `generate()`, because child `_ready()` runs before the parent's and it would otherwise build a map before the seed arrived. Both sides carry a comment — "why doesn't this node generate itself?" is exactly the question someone answers by putting `generate()` back. `randomize_seed` was removed as a second, competing source of randomness; `GameState` already randomises on startup. ## Verification Seed reaches the generator: ``` GameState.run_seed=3017397413 map.map_seed=3017397413 match=true GameState.run_seed=3743863618 map.map_seed=3743863618 match=true GameState.run_seed=1774896844 map.map_seed=1774896844 match=true ``` Same seed reproduces, different seed differs: ``` seed=777 -> 1037 walkable (969 on main landmass) seed=777 -> 1037 walkable (969 on main landmass) seed=778 -> 1492 walkable (879 on main landmass) ``` All four presets verified visually with headed captures — `gl_compatibility` renders nothing headless, so a clean headless run proves nothing about the picture. ## Deliberately deferred - #7 — palette lives in `terrain_grid.gd` as Earth-toned constants, and kind is picked by elevation alone, which makes the crater's floor and exterior share a colour - #8 — the R/T debug keys are not gated out of release builds - #9 — sky and ambient are scene constants, not per-location Pathfinding (`AStar2D`) came across with the POC code but has no consumer until pawns exist. Closes #6
liamjd merged commit d511fff8b5 into main 2026-08-15 15:57:53 +01:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
liamjd/UntitledColonyBuilder!10
No description provided.