requirements iteration
This commit is contained in:
@@ -14,7 +14,7 @@ This document captures the architectural decisions for the project. It is a comp
|
||||
|
||||
A strict separation between the game simulation and the Qt Widgets UI.
|
||||
|
||||
- The **simulation** is a pure C++ library that depends only on Qt Core (QPoint, QVector3D, QRect, etc., as required by the coding guidelines), toml++, and tinyexpr. It contains no QtWidgets, no painting, and no QApplication.
|
||||
- The **simulation** is a pure C++ library that depends only on Qt Core (QPoint, QVector2D, QRect, etc., as required by the coding guidelines), toml++, and tinyexpr. It contains no QtWidgets, no painting, and no QApplication.
|
||||
- The **UI** reads simulation state and renders it. It owns all widgets, painting, and input handling, and drives the simulation via a small command interface (place building, demolish, clear belt tiles, change recipe, set game speed, etc.).
|
||||
|
||||
This split is enforced at the CMake target level (see below). Tests link only against the simulation library and run without a display server.
|
||||
@@ -23,7 +23,7 @@ This split is enforced at the CMake target level (see below). Tests link only ag
|
||||
|
||||
The simulation advances in discrete ticks. All game quantities — production timers, belt item progress, threat accumulation, wave timers, ship cooldowns — are measured in ticks, not wall-clock seconds.
|
||||
|
||||
- Tick rate: fixed (30 or 60 Hz, TBD; choose once and document here).
|
||||
- Tick rate: fixed at 30 Hz.
|
||||
- The outer loop advances `N` ticks per wall-clock frame, where `N` is derived from the selected game speed:
|
||||
- 0× → 0 ticks/frame (pause)
|
||||
- 0.5× → one tick every two frames
|
||||
@@ -42,6 +42,44 @@ Config files (`world.toml`, `buildings.toml`, `recipes.toml`, `ships.toml`, `sta
|
||||
- Formula strings (e.g., threat accumulation, enemy ship level as a function of `t`, per-ship stats as functions of `level`, station stats as functions of generation) are compiled once via `tinyexpr` at load time and stored as callable objects. They are never re-parsed during simulation.
|
||||
- Configs are immutable after load. Any formula that fails to parse, or any required field that is missing or malformed, aborts startup with a clear error message — never mid-game.
|
||||
|
||||
## Coordinate System
|
||||
|
||||
See REQ-GW-COORDS for the authoritative tile-coordinate convention. This section captures the programming-level conventions that follow from it.
|
||||
|
||||
- Tile coordinates are `QPoint(x, y)`. Origin `(0, 0)` is the first space tile (just right of the asteroid's right edge at game start). X grows right; Y grows down.
|
||||
- Asteroid tiles have `x < 0`. Asteroid left-expansions add tiles at increasingly negative X; the origin never shifts, so existing tile coordinates remain stable across expansions.
|
||||
- Continuous world positions (ship centers, scrap drops, projectiles) use `QVector2D` in tile units — one tile = 1.0 world unit. A ship center at `QVector2D(-3.5, 4.0)` sits at the center of the tile 3.5 tiles left of the asteroid's right edge and 4 tiles down from the top.
|
||||
- Rendering multiplies world units by the tile size in pixels (20) at draw time.
|
||||
- Ship position always refers to the ship's center — this is the point used for sensor, attack-range, and hit-detection checks.
|
||||
|
||||
## Core Types
|
||||
|
||||
Simulation types shared across subsystems:
|
||||
|
||||
- `EntityId` — strictly increasing integer handle, allocated centrally by the simulation. Used for ships and scrap drops. Buildings are addressed by their anchor tile, not by `EntityId`.
|
||||
- `Rotation` — enum `{ North, East, South, West }`. The rotation applied to a building's surface_mask when placed.
|
||||
- `BuildingType` — enum covering every building type in requirements.md (Miner, Smelter, Assembler, ReprocessingPlant, Shipyard, SalvageBay, Belt, Splitter, Hq, PlayerDefenceStation, EnemyDefenceStation).
|
||||
- `ItemType` — tagged id of every transportable material (ores, ingots, intermediates, building_blocks, scrap).
|
||||
- `Item` — `struct Item { ItemType type; }`. Items on belts have no persistent identity across ticks.
|
||||
- `Port` — `struct Port { QPoint tile; Rotation direction; }`. Identifies a belt-adjacent cell and the direction of flow across that cell.
|
||||
- `MovementIntent` — `struct MovementIntent { int priority; QVector2D target; }`. Priority follows the order declared under Movement Arbitration. Cleared at the start of each tick; the highest-priority write wins; `tickMovement` reads the winner.
|
||||
|
||||
## Tick Order
|
||||
|
||||
Within a single simulation tick, subsystems run in this fixed order. The order is load-bearing for determinism and for avoiding one-tick-delay artifacts (e.g., items landing on a belt but not advancing in the same tick).
|
||||
|
||||
1. **Wave scheduler** — advance wave timer; on trigger, compute wave composition per REQ-WAV-TRIGGER and schedule spawn times across REQ-WAV-SPAWN-DURATION; spawn any enemy ships whose scheduled time has arrived this tick.
|
||||
2. **Threat accumulation** — add `max(0, threat_rate_formula(t))` × tick_dt to threat level (REQ-WAV-THREAT-RATE).
|
||||
3. **Belt → building pull** — buildings drain eligible items from adjacent belt tiles into per-material input buffers (REQ-MAT-INPUT-PORTS).
|
||||
4. **Building production** — advance production timers; start new cycles when inputs and output-buffer space permit (REQ-MAT-CYCLE); on completion, deposit output.
|
||||
5. **Building → belt push** — buildings push items from output buffer onto the belt tile at their output port (REQ-MAT-OUTPUT-PORT).
|
||||
6. **Belt tick** — advance items along belt tiles; apply splitter routing (REQ-BLD-SPLITTER).
|
||||
7. **Ship behavior systems** — clear `MovementIntent` on each ship, then run `tickThreatResponse`, `tickScrapCollector`, `tickRepairBehavior`, `tickHomeReturn` in any order (arbitration is via intent priority).
|
||||
8. **Combat resolution** — ships and defence stations acquire targets, fire, apply damage; queue deaths.
|
||||
9. **Deaths & loot** — process queued deaths: drop scrap (REQ-RES-SCRAP-DROP), drop blueprints (REQ-DEF-BLUEPRINT-DROP), remove entities.
|
||||
10. **`tickMovement`** — advance ship positions based on final `MovementIntent`.
|
||||
11. **Scrap despawn** — decrement scrap timers; remove expired scrap (REQ-RES-SCRAP-DROP).
|
||||
|
||||
## CMake Target Layout
|
||||
|
||||
Three product targets plus tests:
|
||||
@@ -133,10 +171,10 @@ Behaviors are decomposed, not bundled into per-role monolithic AIs. This is the
|
||||
struct ThreatResponse { float engagementRange; CombatStance stance;
|
||||
CombatTargetPriority priority;
|
||||
std::optional<EntityId> currentTarget; };
|
||||
struct ScrapCollector { std::optional<QVector3D> scrapTarget; EntityId deliveryBay; };
|
||||
struct ScrapCollector { std::optional<QVector2D> scrapTarget; EntityId deliveryBay; };
|
||||
struct RepairBehavior { RepairTargetPriority priority;
|
||||
std::optional<EntityId> currentTarget; };
|
||||
struct HomeReturn { float retreatHpFraction; QVector3D homePos; };
|
||||
struct HomeReturn { float retreatHpFraction; QVector2D homePos; };
|
||||
```
|
||||
|
||||
### Ship
|
||||
@@ -144,8 +182,8 @@ struct HomeReturn { float retreatHpFraction; QVector3D homePos; };
|
||||
```cpp
|
||||
struct Ship {
|
||||
EntityId id;
|
||||
QVector3D position;
|
||||
QVector3D velocity;
|
||||
QVector2D position;
|
||||
QVector2D velocity;
|
||||
float hp;
|
||||
float maxHp;
|
||||
int level;
|
||||
|
||||
Reference in New Issue
Block a user