C++/raylib semi-realistic fantasy/sci-fi planet generator on a fixed icosphere grid (Eulerian: properties flow over fixed cells). World-creation stages: tectonics, continental drift & erosion, hydrology (rivers/lakes), climate (temperature + orographic precipitation), and biome classification. Engine in src/sim (raylib-free, headless-testable), viewer in src/render. See CLAUDE.md and docs/ (design-notes.md, fauna-flora-plan.md = next step). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
83 lines
4.9 KiB
Markdown
83 lines
4.9 KiB
Markdown
# Next step — Fauna & Flora (derived carrying-capacity densities)
|
||
|
||
> Status: **planned, not yet implemented.** This is the next World-Creation stage after
|
||
> climate. Approved design captured here so it can be picked up verbatim (e.g. after the
|
||
> project moves to another machine — the auto-memory does not travel, this doc does).
|
||
|
||
## Decision summary
|
||
|
||
- **Derived carrying-capacity map**, not a live simulation: vegetation + wildlife
|
||
**density scalars** recomputed each tick from the climate fields + terrain, exactly like
|
||
biomes/climate. It answers *"what could live here"*, not *"what is living/evolving here"*.
|
||
- The actual **time-evolving ecosystem** (population growth, migration, predator-prey,
|
||
extinction, seasons, species) is reserved for the future **Live World** real-time mode
|
||
(year/season timescales — not the My geological clock).
|
||
- Fauna uses a **herbivore + carnivore** food-chain split.
|
||
- Fields are **derived / not saved** (deterministic functions of climate) → **no
|
||
save-format change**. New config knobs ride the v6 self-describing save with no break.
|
||
|
||
## Part A — Biosphere fields (`src/sim/`, raylib-free)
|
||
|
||
- **`Planet.hpp`**: declare `void computeBiosphere();` + accessors
|
||
`const std::vector<double>& vegetation()/herbivores()/carnivores() const`. Add scratch
|
||
members `std::vector<double> sVeg, sHerb, sCarn;` (not saved).
|
||
- **New `src/sim/PlanetBiosphere.cpp`** — `Planet::computeBiosphere()` (run *after*
|
||
`computeClimate()`; reads `sTemp` + `sMoist`):
|
||
- **Vegetation (flora)** `sVeg[i] ∈ [0,1]`: `0` on water (`elev ≤ seaLevel`). On land, an
|
||
NPP-style **Liebig minimum** of a temperature factor and a moisture factor:
|
||
- `tF = clamp((sTemp[i] − bioVegTempMin)/(bioVegTempOpt − bioVegTempMin), 0, 1)`
|
||
- `mF = clamp(sMoist[i]/bioVegMoistRef, 0, 1)`
|
||
- `sVeg = min(tF, mF)` → lush warm-wet, ~0 in ice/desert/alpine (cold- or water-limited),
|
||
matching the biomes.
|
||
- **Herbivores** `sHerb[i] = clamp(sVeg[i] · bioHerbProductivity, 0, 1)` (capacity scales
|
||
with plant productivity).
|
||
- **Carnivores** `sCarn[i]`: present only where prey is abundant, ramping with it:
|
||
`sCarn = sHerb > bioCarnPreyMin ? clamp((sHerb − bioCarnPreyMin)/(1 − bioCarnPreyMin)
|
||
· bioCarnScale, 0, 1) : 0` → concentrated in the richest regions (an energy-pyramid feel,
|
||
visually distinct from the broader herbivore pattern).
|
||
- **`src/sim/Planet.cpp` `generate()`**: call `computeBiosphere()` after `classifyBiomes()`.
|
||
|
||
## Part B — Config knobs (`PlanetTypes.hpp` + `PlanetIO.cpp`)
|
||
|
||
Add to `PlanetConfig` + `CONFIG_FIELDS` + `validateConfig`:
|
||
|
||
| key | default | meaning |
|
||
|---|---|---|
|
||
| `bioVegTempMin` | −5 °C | below this, no plant growth |
|
||
| `bioVegTempOpt` | 15 °C | at/above this, temperature isn't limiting |
|
||
| `bioVegMoistRef` | 0.5 | normalized moisture at which water isn't limiting |
|
||
| `bioHerbProductivity` | 0.9 | herbivore capacity per unit vegetation |
|
||
| `bioCarnPreyMin` | 0.30 | min herbivore density to support carnivores |
|
||
| `bioCarnScale` | 1.0 | carnivore density ramp above the prey threshold |
|
||
|
||
## Part C — Rendering (`src/render/`)
|
||
|
||
- **`Colors.{hpp,cpp}`**: `ColorMode` += `Vegetation`, `Herbivores`, `Carnivores`; add
|
||
`vegColor` (barren tan → lush green), `herbColor` (pale → amber/orange), `carnColor`
|
||
(pale → red/violet); extend `colorModeName`.
|
||
- **`Viewer.cpp`**: `recolor()` adds the three cases (read the accessors, empty-guarded);
|
||
`refreshView()` calls `planet.computeBiosphere()` after `classifyBiomes()`.
|
||
- **`ViewerInput.cpp`**: `KEY_EIGHT` → Vegetation, `KEY_NINE` → Herbivores, `KEY_ZERO` →
|
||
Carnivores (each `recolor()`). The top-center view-name label already shows the mode.
|
||
- **`ViewerRender.cpp` `renderHUD`**: controls line gains `8 veg 9 herbiv 0 carniv`.
|
||
- **`Panels.cpp` `cellInfo()`**: add a life line — `vegetation X% herbivores Y%
|
||
carnivores Z%` (guarded on the arrays being sized).
|
||
|
||
## Verification (headless — extend the `src/sim` test set with `PlanetBiosphere.cpp`)
|
||
|
||
- **Vegetation:** 0 on ocean & Ice cells; near-0 on Desert; high (>0.6) on warm-wet Forest;
|
||
all in [0,1]; finite; deterministic.
|
||
- **Fauna food chain:** `sHerb` correlates with `sVeg`; `sCarn[i] > 0 ⇒ sHerb[i] >
|
||
bioCarnPreyMin` and carnivore-positive cells are a strict subset of herbivore-rich cells;
|
||
all in [0,1]; deterministic.
|
||
- `test_logic`, biomes+config, climate suites still pass; app builds clean; no save change.
|
||
- **GUI:** `8` lush green continents thinning to barren in deserts/poles/peaks; `9` grazer
|
||
density following productivity; `0` predators concentrated in the richest belts; cell info
|
||
shows vegetation/herbivore/carnivore %.
|
||
|
||
## Out of scope (future / Live World)
|
||
|
||
Time-evolving populations (growth, migration, predator-prey, extinction), seasons, and
|
||
species/typed organisms — all part of the future **Live World** real-time simulation that
|
||
runs the finished planet at hours/days/weeks/months with dynamic weather + life.
|