laser requirements
This commit is contained in:
@@ -63,6 +63,22 @@ Simulation types shared across subsystems:
|
||||
- `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.
|
||||
- `FireEvent` — `struct FireEvent { EntityId shooter; EntityId target; Tick emittedAt; }`. Transient record emitted each time a weapon fires (REQ-SHP-FIRING, REQ-SHP-FIRING-BEAM). Buffered in a sim-owned queue and drained by the renderer; see Sim → UI Events.
|
||||
|
||||
## Sim → UI Events
|
||||
|
||||
The sim owns a small set of per-frame event queues that the UI drains on each render. These carry one-shot signals that are not derivable from persistent state — notably weapon fires (REQ-SHP-FIRING-BEAM). Additional event types can be added here later (e.g., building-complete, unit-death flashes) without changing the pattern.
|
||||
|
||||
Implementation: a plain `std::vector<FireEvent>` owned by `Simulation`, one vector per event type. Combat resolution (tick-order step 8) appends to it. The UI calls `simulation.drainFireEvents()` once per rendered frame, which returns the accumulated vector by move and clears the internal one. Beams are tracked by the renderer for 0.3 s of wall time (9 ticks at 30 Hz) using the events' `emittedAt` tick, then discarded. If either the shooter or target entity is gone when the renderer looks them up, the beam is dropped early.
|
||||
|
||||
We deliberately do **not** use `QObject` signals/slots or `QEvent`:
|
||||
|
||||
- **Determinism.** A plain ordered vector preserves tick-order exactly; the queue is part of per-tick state, inspectable in tests.
|
||||
- **Sim/UI seam.** The sim exposes pull-style access only; the UI never subscribes into the sim, keeping the simulation/presentation split clean.
|
||||
- **Headless testability.** Catch2 tests read the queue directly after `tick()`; no event loop, no `QApplication`.
|
||||
- **Zero overhead.** Sim types remain plain structs — no `QObject`, no moc, no signal dispatch machinery.
|
||||
|
||||
If the number of event types grows past a handful, we can wrap them in a small `EventQueue<T>` template, still owned by the sim. Signals/slots would only be warranted if we needed multiple independent subscribers or cross-thread dispatch, and we need neither.
|
||||
|
||||
## Tick Order
|
||||
|
||||
@@ -75,7 +91,7 @@ Within a single simulation tick, subsystems run in this fixed order. The order i
|
||||
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.
|
||||
8. **Combat resolution** — ships and defence stations acquire targets, fire, apply damage; queue deaths. Each fire appends a `FireEvent` to the sim's fire-event queue (REQ-SHP-FIRING-BEAM).
|
||||
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).
|
||||
|
||||
@@ -104,6 +104,8 @@ Output port indicators are not building tiles themselves. A building may have mo
|
||||
- REQ-SHP-MOVEMENT: Ships move in straight lines toward their current destination at the speed defined by their speed formula. Ship position refers to the ship's center for all range, sensor, and attack checks.
|
||||
- REQ-SHP-NO-COLLISION: Ships do not collide with each other or with defence stations; they may visually overlap.
|
||||
- REQ-SHP-SENSOR: A ship perceives only entities within its sensor range. Behavior is driven by what is in sensor range; entities outside sensor range are ignored.
|
||||
- REQ-SHP-FIRING: All weapons — on ships and on defence stations — are hitscan lasers. When a weapon is off cooldown and its target is within attack range, it fires: damage is applied instantly to the target with no projectile entity, no travel time, and no intervening collision. The weapon's cooldown then begins, derived from its fire rate formula.
|
||||
- REQ-SHP-FIRING-BEAM: Each fire event produces a visual laser beam drawn from the shooter's position to the target's position for 0.3 seconds. The beam is a pure rendering effect and has no simulation state (does not block movement, does not re-apply damage over its lifetime). Beams follow the shooter and target positions if either moves during the 0.3-second window.
|
||||
- REQ-SHP-ENEMY-AI: Enemy ships engage the closest valid target (player defence station, HQ, or player ship) within their sensor range. If no target is in sensor range, they move toward the asteroid (leftward in world coordinates).
|
||||
- REQ-SHP-COMBAT: **Combat ships** — move right through space and engage enemy ships. The player can configure the following per shipyard (applied to all ships produced by that shipyard):
|
||||
- Stance: aggressive (advance toward enemies) / defensive (hold position near asteroid).
|
||||
|
||||
Reference in New Issue
Block a user