Create the main game scene: terrain grid, camera rig, environment #6

Closed
opened 2026-08-15 12:57:11 +01:00 by liamjd · 0 comments
Owner

Stand up res://scenes/game.tscn as the first playable-adjacent scene: a seeded terrain grid under an orthographic camera, lit, with working pan/zoom/rotate. No pawns, no building, no UI.

This is the consumer the seed work (#1, #2, #3) was built for — until it exists, GameState.run_seed is unobservable.

Target tree

Game (Node3D)                 scripts/game.gd — wiring and setup
├── Map (GridMap)             scripts/terrain_grid.gd — generates its own MeshLibrary and cells
├── CameraRig (Node3D)        scripts/camera_rig.gd — focus point on the ground, carries yaw
│   └── Camera3D              orthographic, on a fixed boom, carries pitch
├── WorldEnvironment          procedural sky, sky-sourced ambient
└── Sun (DirectionalLight3D)  shadows on

Menu wiring: _start_new_game() in main_menu.gd changes to this scene after setting GameState.run_seed, and the temporary print() comes out.

Seed threading

terrain_grid.gd must not read GameState directly. Take the seed as an exported/settable property, and let game.gd pass GameState.run_seed in during setup.

This keeps the generator testable in isolation and stops the autoload becoming an implicit dependency of every system — which matters more later, when threat cycles and contracts also want deterministic seeding off the same run seed.

Reference, not template

C:\Development\Games\OrthographicGame solves this exact problem and its CLAUDE.md documents constraints found by failing at them. Read it first. Carry over the load-bearing mechanics:

  • Heights quantised into integer levels so the ground terraces — the defining visual constraint. No continuous mesh, no smoothing that hides the steps.
  • MeshLibrary generated at runtime; no authored .meshlib, no art assets. MeshLibrary has no per-item material override in 4.7, so colour bakes onto each mesh via PrimitiveMesh.material.
  • Tiles are full-depth columns, not slabs — GridMap allows one item per cell, so a tile draws its own cliff face down past its lowest neighbour. Slabs leave holes.
  • Collider is a single cube at the top, not the whole column, or click raycasts pick the tile behind a cliff.
  • Noise sampling needs the normalisation pass: fractal Perlin only reaches a fraction of its nominal range, so sampling straight into height_scale gives a near-flat map.
  • Camera: yaw on the rig, pitch on the camera, zoom changes Camera3D.size (never the boom length), pan speed scales with zoom.

Deliberately reconsider

The POC generates a radial-falloff island in a sea. That was a terrain-generation testbed, not this game's map. Worth deciding fresh:

  • Is the map an island at all? A moon colony reads better as a crater basin, a rift valley, or open regolith with elevation. Water may not belong.
  • Map size and level_height should follow the colony footprint we expect, not the POC's numbers.
  • falloff_start = 0.80 was fitted to guarantee reachable pawn spawns. With no pawns yet, that constraint does not apply — do not port the value without the reason.
  • Terrain kinds should anticipate resource nodes (#TBD) rather than the POC's meadow/rock/sand palette.

Pathfinding (AStar2D, edge-based walkability) is out of scope — no pawns yet. Do not port it speculatively.

Done when

  • New Game from the menu lands in the scene with a generated map.
  • The same seed produces the same map; a different seed produces a different one. This is the first real test of the seed pipeline.
  • Camera pans, zooms and rotates over the terrain without clipping it.
  • Verified headed with a screenshot — gl_compatibility renders nothing headless, so a clean headless run proves nothing visual.

May well split into separate terrain / camera issues if it gets unwieldy.

Stand up `res://scenes/game.tscn` as the first playable-adjacent scene: a seeded terrain grid under an orthographic camera, lit, with working pan/zoom/rotate. No pawns, no building, no UI. This is the consumer the seed work (#1, #2, #3) was built for — until it exists, `GameState.run_seed` is unobservable. ## Target tree ``` Game (Node3D) scripts/game.gd — wiring and setup ├── Map (GridMap) scripts/terrain_grid.gd — generates its own MeshLibrary and cells ├── CameraRig (Node3D) scripts/camera_rig.gd — focus point on the ground, carries yaw │ └── Camera3D orthographic, on a fixed boom, carries pitch ├── WorldEnvironment procedural sky, sky-sourced ambient └── Sun (DirectionalLight3D) shadows on ``` Menu wiring: `_start_new_game()` in `main_menu.gd` changes to this scene after setting `GameState.run_seed`, and the temporary `print()` comes out. ## Seed threading `terrain_grid.gd` must **not** read `GameState` directly. Take the seed as an exported/settable property, and let `game.gd` pass `GameState.run_seed` in during setup. This keeps the generator testable in isolation and stops the autoload becoming an implicit dependency of every system — which matters more later, when threat cycles and contracts also want deterministic seeding off the same run seed. ## Reference, not template `C:\Development\Games\OrthographicGame` solves this exact problem and its CLAUDE.md documents constraints found by failing at them. Read it first. Carry over the load-bearing mechanics: - Heights **quantised into integer levels** so the ground terraces — the defining visual constraint. No continuous mesh, no smoothing that hides the steps. - `MeshLibrary` generated at runtime; no authored `.meshlib`, no art assets. `MeshLibrary` has no per-item material override in 4.7, so colour bakes onto each mesh via `PrimitiveMesh.material`. - Tiles are **full-depth columns**, not slabs — GridMap allows one item per cell, so a tile draws its own cliff face down past its lowest neighbour. Slabs leave holes. - **Collider is a single cube at the top**, not the whole column, or click raycasts pick the tile behind a cliff. - Noise sampling needs the **normalisation pass**: fractal Perlin only reaches a fraction of its nominal range, so sampling straight into `height_scale` gives a near-flat map. - Camera: yaw on the rig, pitch on the camera, zoom changes `Camera3D.size` (never the boom length), pan speed scales with zoom. ## Deliberately reconsider The POC generates a radial-falloff **island** in a sea. That was a terrain-generation testbed, not this game's map. Worth deciding fresh: - Is the map an island at all? A moon colony reads better as a crater basin, a rift valley, or open regolith with elevation. Water may not belong. - Map size and `level_height` should follow the colony footprint we expect, not the POC's numbers. - `falloff_start = 0.80` was fitted to guarantee reachable pawn spawns. With no pawns yet, that constraint does not apply — do not port the value without the reason. - Terrain *kinds* should anticipate resource nodes (#TBD) rather than the POC's meadow/rock/sand palette. Pathfinding (`AStar2D`, edge-based walkability) is **out of scope** — no pawns yet. Do not port it speculatively. ## Done when - New Game from the menu lands in the scene with a generated map. - The same seed produces the same map; a different seed produces a different one. This is the first real test of the seed pipeline. - Camera pans, zooms and rotates over the terrain without clipping it. - Verified **headed** with a screenshot — `gl_compatibility` renders nothing headless, so a clean headless run proves nothing visual. May well split into separate terrain / camera issues if it gets unwieldy.
Sign in to join this conversation.
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#6
No description provided.