9. Simulation And ECS
EchoWarrior is migrating toward pure, testable systems without forcing a risky rewrite of the playable runtime.
That creates a bridge architecture:
PrototypeRuntimestill owns the live Macroquad actor lists used for drawing and input.- Pure modules in
src/gameown reusable rules and testable state machines. - The ECS lifecycle bridge mirrors key runtime entities into
EcsWorld.
Current Ownership
Section titled “Current Ownership”flowchart TB runtime[PrototypeRuntime] actors[Runtime actor structs<br/>player, enemies, NPCs] ecsbridge[EcsLifecycleBridge] ecs[EcsWorld] pure[src/game pure systems] draw[Runtime draw paths]
runtime --> actors actors --> draw runtime --> ecsbridge ecsbridge --> ecs ecs --> pure pure --> runtimeThe runtime remains the playable source of truth for Macroquad-facing state. The ECS mirror exists so shared systems can grow without a big-bang migration.
ECS Lifecycle Bridge
Section titled “ECS Lifecycle Bridge”sequenceDiagram participant Runtime as PrototypeRuntime participant Bridge as EcsLifecycleBridge participant ECS as EcsWorld
Runtime->>Bridge: enemy spawned Bridge->>ECS: create entity + components Runtime->>Bridge: frame sync position/health Bridge->>ECS: update components Runtime->>Bridge: enemy dies/despawns Bridge->>ECS: retire entity Runtime->>Bridge: restore save Bridge->>ECS: rebuild mirrored lifecycle stateThis bridge should stay narrow. Avoid creating a second entity ownership model beside it.
Pure Run Kernel
Section titled “Pure Run Kernel”src/game/run_sim.rs is a pure run simulation boundary. It can test core run behavior without a window.
flowchart LR input[Test or runtime slice] sim[RunSimulation] combat[damage / XP / level-up logic] events[Run event journal] save[save-shaped snapshot]
input --> sim --> combat combat --> events sim --> saveUse this style when extracting logic from runtime:
- identify the deterministic rule
- move the rule into
src/game - keep runtime as adapter/application layer
- add pure tests
ECS World Shape
Section titled “ECS World Shape”At a high level, EcsWorld is a sparse-set component store:
flowchart TB entity[EntityId] transform[Transform] motion[Motion] health[Health] combat[CombatStats] tags[EffectTag / Lifetime] query[queries like query_alive]
entity --> transform entity --> motion entity --> health entity --> combat entity --> tags transform --> query health --> queryquery_alive() is the important current query boundary: systems can ask for finite, positive-health spawned actors without knowing runtime internals.
Contributor Guidance
Section titled “Contributor Guidance”| If you are doing this… | Prefer |
|---|---|
| adding a pure rule | src/game with tests |
| changing visible actor state | runtime owner plus bridge sync if needed |
| adding ECS components | update bridge and pure queries together |
| changing save restore for enemies | ensure ECS mirror rebuilds correctly |
| adding a second entity list | do not; extend the existing bridge/model |
Good Extraction Candidates
Section titled “Good Extraction Candidates”Good candidates for pure extraction:
- targeting rules
- cooldown/rate-limit math
- spawn schedule helpers
- offer selection
- XP/progression arithmetic
- hitstop/state machine logic
- pathfinding/nav rules
Poor candidates:
- draw order
- texture handles
- shader uniforms
- audio playback handles
- camera render-target details