652 lines
22 KiB
Markdown
652 lines
22 KiB
Markdown
# Side Scroller Shooter Groundwork
|
|
|
|
## Goal
|
|
This document defines the technical foundation for a classic 2D side scroller shooter built with Godot 4 and C#. The framework must support the whole genre family, not a single game design: player movement, weapons, enemies, bosses, pickups, scrolling levels, scripted encounters, layered music, overlapping sound effects, and strong debugging tools. Final game-specific rules and content will be built later on top of this groundwork.
|
|
|
|
The non-negotiable constraint is that **all authoritative gameplay simulation lives in one pure .NET project with no Godot dependency**. Godot is the host for rendering, input capture, authoring UX, audio playback, and debug tooling. The same simulation assembly is referenced by both xUnit tests and the Godot host so all gameplay logic can be verified without engine or multimedia interference.
|
|
|
|
## Hard Constraints
|
|
1. **Single pure simulation project**. Do not split runtime gameplay and content definitions into separate assemblies unless a real dependency problem appears later.
|
|
2. **Deterministic fixed-step simulation**. The same content, seed, and input action stream must produce the same state and hashes every run.
|
|
3. **Serializable input actions**. The simulation consumes serializable action batches so recorded runs can be replayed exactly.
|
|
4. **Serializable full state**. The entire simulation state must be serializable for save/load, replay checkpoints, and desync verification.
|
|
5. **Thin Godot host**. Godot must not become gameplay authority for physics, damage, AI, triggers, or progression.
|
|
6. **xUnit-first verification**. The simulation project is expected to reach 100% gameplay coverage; exclusions are acceptable only for clearly non-logic code such as generated tables or serializer boilerplate.
|
|
|
|
## Repository Layout
|
|
The Godot project should **not** live at repository root. With SDK-style .NET projects, a root-level Godot `.csproj` will glob in files from subfolders, which makes it too easy to accidentally compile tests and simulation sources into the Godot assembly.
|
|
|
|
Recommended layout:
|
|
|
|
```text
|
|
/SideScrollerGame.sln
|
|
/src/SideScrollerGame.Sim/
|
|
SideScrollerGame.Sim.csproj
|
|
/FixPoint/ # preferred final home
|
|
/Definitions/
|
|
/Runtime/
|
|
/Systems/
|
|
/Serialization/
|
|
/Replay/
|
|
/Verification/
|
|
/tests/SideScrollerGame.Sim.Tests/
|
|
SideScrollerGame.Sim.Tests.csproj
|
|
/godot/
|
|
project.godot
|
|
SideScrollerGame.Godot.csproj
|
|
/.godot/
|
|
/scenes/
|
|
/scripts/host/
|
|
/assets/
|
|
/addons/
|
|
/content/compiled/
|
|
/tools/
|
|
```
|
|
|
|
Current repository note:
|
|
- The existing root `FixPoint/` folder is acceptable during bootstrap.
|
|
- The preferred end state is to move it under `src/SideScrollerGame.Sim/FixPoint/` and adjust namespaces once the simulation project is created.
|
|
- The Godot project should be moved under `/godot` before the real solution structure grows.
|
|
|
|
Dependency rules:
|
|
|
|
```text
|
|
Godot Host -> SideScrollerGame.Sim
|
|
Tests -> SideScrollerGame.Sim
|
|
Sim -> no Godot references
|
|
```
|
|
|
|
Within the simulation project, separate concerns by namespaces and folders, not by extra assemblies:
|
|
- `SideScrollerGame.Sim.Math`
|
|
- `SideScrollerGame.Sim.Definitions`
|
|
- `SideScrollerGame.Sim.Runtime`
|
|
- `SideScrollerGame.Sim.Systems`
|
|
- `SideScrollerGame.Sim.Serialization`
|
|
- `SideScrollerGame.Sim.Replay`
|
|
- `SideScrollerGame.Sim.Verification`
|
|
|
|
## Assembly Responsibilities
|
|
### `SideScrollerGame.Sim`
|
|
- fixed-step world simulation
|
|
- immutable gameplay and level definitions
|
|
- deterministic numeric types and RNG
|
|
- physics and collision
|
|
- AI and behavior execution
|
|
- input action ingestion
|
|
- save/load serialization
|
|
- replay support
|
|
- debug hashes and verification hooks
|
|
|
|
### `SideScrollerGame.Godot`
|
|
- editor bootstrapping
|
|
- converting physical input into simulation actions
|
|
- fixed-step runner and interpolation
|
|
- rendering and presentation node lifecycle
|
|
- animation mapping
|
|
- audio playback, music queue, and cross-fading
|
|
- authoring and validation tools
|
|
- development-time timeline controls
|
|
|
|
## Simulation Boundaries
|
|
The simulation owns:
|
|
- world state
|
|
- movement and collision
|
|
- weapon firing and ammo
|
|
- enemy behavior
|
|
- spawn logic
|
|
- damage, death, score, drops, checkpoints
|
|
- scripted triggers
|
|
- camera gameplay rules
|
|
- music state requests
|
|
|
|
The Godot host owns:
|
|
- drawing sprites, meshes, parallax, particles, and UI
|
|
- collecting OS input and converting it to actions
|
|
- audio stream playback and mixing
|
|
- interpolation between snapshots
|
|
- editor tooling and authoring UX
|
|
- developer overlays and transport controls
|
|
|
|
Godot physics, animation trees, collision layers, and timers must never become authoritative for gameplay.
|
|
|
|
## Deterministic Simulation Model
|
|
Use a fixed rate of **60 simulation ticks per second**. This is appropriate for classic side scroller shooters and is easy to reason about. Rendering can run faster or slower; simulation must not.
|
|
|
|
Determinism rules:
|
|
- no floating-point math in simulation logic
|
|
- no use of `DateTime`, wall clock, threads, async work, GUIDs, or nondeterministic iteration order
|
|
- stable entity iteration order
|
|
- immutable definitions after load
|
|
- deterministic RNG with explicit persisted state
|
|
- all simulation outputs derived only from definitions, current state, seed, and action stream
|
|
|
|
Numerics:
|
|
- use fixed-point math throughout the simulation
|
|
- represent position, velocity, and acceleration in deterministic units
|
|
- keep map sizes and tile sizes as integer values
|
|
|
|
The current `FixPoint/` folder should be treated as simulation infrastructure, not Godot host code.
|
|
|
|
## Simulation API
|
|
The simulation should expose a narrow runner API that is safe for tests, replays, and Godot hosting:
|
|
|
|
```csharp
|
|
public sealed class Simulation
|
|
{
|
|
public Simulation(GameDefinition gameDefinition, SimulationConfig config, int seed);
|
|
|
|
public int CurrentTick { get; }
|
|
public SimulationState CurrentState { get; }
|
|
public WorldSnapshot PreviousSnapshot { get; }
|
|
public WorldSnapshot CurrentSnapshot { get; }
|
|
|
|
public TickResult Step(in TickActionBatch actions);
|
|
|
|
public byte[] SaveState();
|
|
public static Simulation LoadState(byte[] data, GameDefinition gameDefinition, SimulationConfig config);
|
|
}
|
|
```
|
|
|
|
`TickResult` should contain:
|
|
- gameplay events
|
|
- presentation events
|
|
- sound requests
|
|
- music requests
|
|
- spawn/despawn notifications
|
|
- per-tick debug hash
|
|
- optional verification report
|
|
|
|
## Input Model and Replay Format
|
|
The simulation should receive user intent through serializable actions, not direct polling state.
|
|
|
|
Recommended approach:
|
|
- Godot host converts raw keyboard/gamepad input into `SimulationAction` records
|
|
- each tick receives a `TickActionBatch`
|
|
- continuous controls are handled by edge-triggered actions plus persistent input state inside the simulation
|
|
|
|
Example action model:
|
|
|
|
```csharp
|
|
public abstract record SimulationAction;
|
|
|
|
public sealed record MoveAxisChanged(PlayerId PlayerId, sbyte X, sbyte Y) : SimulationAction;
|
|
public sealed record AimAxisChanged(PlayerId PlayerId, short X, short Y) : SimulationAction;
|
|
public sealed record ButtonChanged(PlayerId PlayerId, InputButton Button, bool IsPressed) : SimulationAction;
|
|
public sealed record WeaponSlotSelected(PlayerId PlayerId, int SlotIndex) : SimulationAction;
|
|
|
|
public sealed record TickActionBatch(int Tick, ImmutableArray<SimulationAction> Actions);
|
|
```
|
|
|
|
Why this matters:
|
|
- the exact action stream can be recorded to disk
|
|
- bug reports can attach a replay instead of describing a scenario
|
|
- tests can load recorded runs and verify hashes
|
|
- stepping to tick `N` is just replay plus optional checkpoint restore
|
|
|
|
Replay file contents:
|
|
- content hash or version id
|
|
- simulation config
|
|
- seed
|
|
- initial level/start condition
|
|
- per-tick action batches
|
|
- optional periodic serialized state checkpoints
|
|
|
|
## Full State Serialization
|
|
The entire simulation state must be serializable. This is not just for player save games. It is also required for:
|
|
- replay checkpoints
|
|
- fast-forward and jump-to-tick tooling
|
|
- save/load correctness verification
|
|
- deterministic debugging
|
|
|
|
`SimulationState` should include:
|
|
- current tick
|
|
- active level and checkpoint
|
|
- all runtime entities and subsystem state
|
|
- timers and cooldowns
|
|
- RNG state
|
|
- squad and flock coordination state
|
|
- scripted trigger state
|
|
- camera gameplay state
|
|
- pending spawn queues
|
|
- music/gameplay progression state
|
|
- player input hold state
|
|
|
|
Serialization guidance:
|
|
- use an explicit versioned serializer owned by the simulation project
|
|
- avoid relying on Godot serialization
|
|
- keep format deterministic and stable
|
|
- support both compact runtime format and optional debug-friendly dump format if useful
|
|
|
|
## Built-In Desync Verification
|
|
During development, each step should optionally verify save/load correctness and step determinism by round-tripping a clone.
|
|
|
|
Recommended `VerificationMode`:
|
|
- `None`
|
|
- `RoundTripState`
|
|
- `RoundTripAndStepClone`
|
|
|
|
`RoundTripAndStepClone` algorithm for each tick:
|
|
1. serialize the live simulation
|
|
2. deserialize a clone from those bytes
|
|
3. compare live and clone state hashes or normalized snapshots
|
|
4. apply the same `TickActionBatch` to both instances
|
|
5. compare resulting states again
|
|
6. report any mismatch with tick number, subsystem, and serialized artifacts
|
|
|
|
This catches two different problems:
|
|
- **save/load desync**: serialization fails to reconstruct the same state
|
|
- **step desync**: cloned and live instances diverge when stepping the same input
|
|
|
|
This mode is expensive and should be optional, but it is exactly the right tool for early framework development.
|
|
|
|
## Runtime Debug Time Controls
|
|
Development UX must support stepping and replay inspection from day one.
|
|
|
|
Required transport controls:
|
|
- `Restart`
|
|
- `Play/Pause`
|
|
- `Advance One Step`
|
|
- `Fast Forward To Step X`
|
|
|
|
Recommended supporting features:
|
|
- current tick display
|
|
- current replay seed
|
|
- state hash display
|
|
- verification on/off toggle
|
|
- playback speed multiplier
|
|
- jump to checkpoint
|
|
- scrub to nearest saved checkpoint, then replay to requested tick
|
|
|
|
Implementation guidance:
|
|
- maintain a `RunController` in the Godot host
|
|
- cache serialized checkpoints every `N` ticks to make fast-forward practical
|
|
- treat restart as reloading the initial seed, content, and replay
|
|
- do not let presentation-only pause state alter simulation state
|
|
|
|
## World Representation
|
|
Avoid a generic ECS. A domain-specific, data-oriented model is a better fit for this genre.
|
|
|
|
Recommended runtime state groups:
|
|
- `PlayerState`
|
|
- `EnemyState`
|
|
- `ProjectileState`
|
|
- `PickupState`
|
|
- `HazardState`
|
|
- `PlatformState`
|
|
- `TriggerState`
|
|
- `CameraState`
|
|
- `LevelRuntimeState`
|
|
- `SquadState`
|
|
|
|
Cross-cutting concepts:
|
|
- `EntityId`
|
|
- faction/team
|
|
- transform
|
|
- velocity
|
|
- health and armor
|
|
- hurtboxes and hitboxes
|
|
- timers and modifiers
|
|
- presentation state keys
|
|
|
|
Keep definitions immutable and runtime state mutable.
|
|
|
|
## Fixed Tick Pipeline
|
|
Each tick should run in a fixed order:
|
|
|
|
1. apply incoming actions to player input state
|
|
2. advance timers, cooldowns, modifiers, and scripted sequences
|
|
3. update AI, squad logic, and flocking decisions
|
|
4. resolve weapon intents and spawn projectiles/effects
|
|
5. integrate movement
|
|
6. resolve map, platform, and environment collision
|
|
7. resolve projectile, melee, and contact hits
|
|
8. apply damage, knockback, deaths, drops, score, and checkpoint changes
|
|
9. process triggers, camera rules, wave progression, and music state transitions
|
|
10. build events, snapshots, and hashes
|
|
|
|
This order must remain explicit and stable. New systems should be inserted deliberately, not opportunistically.
|
|
|
|
## Physics and Collision
|
|
The simulation owns all gameplay physics.
|
|
|
|
Recommended model:
|
|
- 2D kinematic actors
|
|
- deterministic AABB-based collision for actors
|
|
- tile-grid collision for level geometry
|
|
- one-way platforms
|
|
- ladders and climb volumes
|
|
- hazard and water zones
|
|
- deterministic moving platforms
|
|
- sweep or raycast projectile movement to avoid tunneling
|
|
|
|
Movement design targets:
|
|
- grounded movement
|
|
- coyote time and jump buffering
|
|
- crouch and stance-dependent hitboxes
|
|
- knockback and stun
|
|
- moving platform carry behavior
|
|
- optional slopes later if needed
|
|
|
|
Do not use Godot rigid bodies as gameplay authority.
|
|
|
|
## Frame Interpolation
|
|
Rendering should interpolate between two authoritative simulation snapshots.
|
|
|
|
Godot host loop:
|
|
1. accumulate real frame time
|
|
2. run zero or more fixed simulation steps
|
|
3. compute interpolation alpha
|
|
4. render between `PreviousSnapshot` and `CurrentSnapshot`
|
|
|
|
Interpolate:
|
|
- position
|
|
- aim direction
|
|
- camera anchor
|
|
- recoil offsets
|
|
|
|
Do not interpolate:
|
|
- deaths
|
|
- pickups
|
|
- state machine transitions
|
|
- damage flashes
|
|
- spawn and despawn boundaries
|
|
|
|
Presentation nodes should be mapped by `EntityId` and recreated only on tick boundaries.
|
|
|
|
## Animation Model
|
|
The simulation should emit semantic animation state, not Godot clip names.
|
|
|
|
Example semantic outputs:
|
|
- locomotion: `Idle`, `Run`, `JumpRise`, `JumpFall`, `Land`, `Crouch`, `Climb`
|
|
- combat: `Fire`, `Reload`, `Charge`, `Melee`, `Overheat`
|
|
- damage: `Hurt`, `Invulnerable`, `Dead`
|
|
- modifiers: facing, aim sector, grounded, wet, frozen, heavy_weapon
|
|
|
|
The Godot host maps semantic state to `AnimationTree`, sprite animations, blend spaces, or custom timelines.
|
|
|
|
## Audio Architecture
|
|
The simulation emits logical audio requests; the Godot host performs actual playback.
|
|
|
|
### Overlapping Sound Effects
|
|
Simulation should emit `SoundEvent` data:
|
|
- cue id
|
|
- source entity or world position
|
|
- category/bus
|
|
- priority
|
|
- optional pitch/variant seed
|
|
|
|
The Godot host should:
|
|
- pool multiple audio players
|
|
- allow overlapping playback for repeated weapons and explosions
|
|
- cap voices per cue and bus
|
|
- support both positional and UI sounds
|
|
|
|
### Cross-Fading Music Queue
|
|
The simulation should emit logical music requests, not manipulate players directly.
|
|
|
|
Recommended requests:
|
|
- `Queue(trackId)`
|
|
- `Replace(trackId, fadeOutTicks, fadeInTicks)`
|
|
- `PushPriority(trackId)`
|
|
- `PopPriority(trackId)`
|
|
- `Stop(fadeOutTicks)`
|
|
|
|
The Godot host should implement a `MusicDirector` with:
|
|
- at least two music players for cross-fading
|
|
- support for intro, loop, and optional outro segments
|
|
- deterministic transitions triggered from simulation ticks
|
|
- queue inspection in the debug UI
|
|
|
|
## Gameplay Definitions
|
|
Definitions live inside the simulation project under `Definitions/` and are loaded from compiled engine-agnostic data.
|
|
|
|
### HeroDefinition
|
|
Include:
|
|
- id, tags, display info
|
|
- collider and stance shapes
|
|
- health, armor, lives, invulnerability ticks
|
|
- movement profile
|
|
- weapon loadout
|
|
- pickup interaction rules
|
|
- animation profile id
|
|
- sound profile id
|
|
|
|
### EnemyDefinition
|
|
Include:
|
|
- id, archetype, faction, tags
|
|
- collider and hurtboxes
|
|
- health and contact damage
|
|
- movement profile
|
|
- behavior definition id
|
|
- squad role support
|
|
- weapon set
|
|
- score reward and drop table
|
|
- boss phase data when needed
|
|
|
|
### WeaponDefinition
|
|
Include:
|
|
- slot type
|
|
- fire mode
|
|
- cadence and burst settings
|
|
- ammo and reload rules
|
|
- muzzle offsets
|
|
- projectile or hitscan profile
|
|
- recoil, spread, and status effects
|
|
- animation and audio ids
|
|
|
|
### ProjectileDefinition
|
|
Include:
|
|
- speed and lifetime
|
|
- gravity scale
|
|
- collider
|
|
- collision mask
|
|
- pierce behavior
|
|
- hit response
|
|
- damage payload
|
|
- explosion or follow-up spawn ids
|
|
|
|
### PowerUpDefinition
|
|
Include:
|
|
- pickup type
|
|
- effect payload
|
|
- duration
|
|
- stacking policy
|
|
- despawn rules
|
|
- magnet behavior
|
|
- audio and presentation ids
|
|
|
|
### Modifier Model
|
|
Use a shared modifier system for buffs and debuffs:
|
|
- additive and multiplicative stat changes
|
|
- capability flags
|
|
- timed effects
|
|
- stack limits
|
|
- refresh behavior
|
|
|
|
## Behavior Framework
|
|
Use a data-driven hierarchical state machine model with reusable sensors and actions. Do not rely on Godot scripts for enemy logic.
|
|
|
|
Reusable sensors:
|
|
- target in range
|
|
- line of sight
|
|
- ground ahead
|
|
- wall ahead
|
|
- recently damaged
|
|
- timer elapsed
|
|
- squad signal received
|
|
|
|
Reusable actions:
|
|
- move
|
|
- stop
|
|
- jump
|
|
- fire
|
|
- dodge
|
|
- retreat
|
|
- strafe
|
|
- hover
|
|
- call squad action
|
|
|
|
### Squadrons and Flocking
|
|
The behavior framework must also support coordinated enemies, not just isolated actors.
|
|
|
|
Required concepts:
|
|
- `SquadDefinition`
|
|
- `SquadState`
|
|
- leader/follower roles
|
|
- formation anchor and slots
|
|
- shared target selection
|
|
- squad orders such as attack, regroup, retreat, flank
|
|
- separation, cohesion, and alignment style flocking for flyers or swarms
|
|
|
|
Use flocking as a tunable subsystem, not a hard-coded enemy type. The simulation should support:
|
|
- loose flying swarms
|
|
- tight escort formations
|
|
- attack waves that break formation temporarily
|
|
- rejoin logic after disruption
|
|
|
|
## Level Data Structure
|
|
Levels must support both authored geometry and deterministic encounter scripting.
|
|
|
|
Recommended `LevelDefinition`:
|
|
- metadata and dimensions
|
|
- tile layers and collision/material map
|
|
- spawn markers
|
|
- pickups and hazards
|
|
- moving platforms and paths
|
|
- checkpoints
|
|
- trigger zones
|
|
- encounter and wave definitions
|
|
- camera zones and locks
|
|
- music zones and scripted transitions
|
|
- scripted event graph
|
|
|
|
Keep authored Godot scenes as input to a compile/export step. The simulation and tests should run on compiled runtime data, not raw scene trees.
|
|
|
|
## Level Editing UX in Godot
|
|
Godot should be used as the authoring front-end, but authored scenes must compile into engine-agnostic runtime definitions.
|
|
|
|
Recommended workflow:
|
|
1. author level scenes in Godot
|
|
2. place custom marker nodes for spawns, triggers, checkpoints, patrol paths, squad anchors, and music zones
|
|
3. validate the authoring scene
|
|
4. compile to runtime content under `content/compiled/`
|
|
5. run game and tests against compiled data
|
|
|
|
Required authoring UX:
|
|
- custom inspector editors for definitions and references
|
|
- gizmos for triggers, camera bounds, paths, and squad formations
|
|
- validation panel for bad ids, overlapping markers, broken references, and invalid encounter setups
|
|
- buttons for `Validate`, `Compile`, and `Play From Here`
|
|
- preview of wave timing, camera rules, and music transitions where practical
|
|
|
|
## Content Pipeline
|
|
There is still a distinction between authoring content and runtime content, but it does not justify a separate assembly.
|
|
|
|
Authoring content:
|
|
- Godot scenes and resources
|
|
- marker nodes and editor-only metadata
|
|
|
|
Compiled runtime content:
|
|
- engine-agnostic serialized definitions
|
|
- loaded by the simulation project
|
|
- used identically by tests and the Godot host
|
|
|
|
Compilation should:
|
|
- resolve references
|
|
- validate identifiers and links
|
|
- flatten authored data into deterministic DTOs
|
|
- assign stable content hashes
|
|
- produce clear compile errors
|
|
|
|
## Save/Load, Replay, and Debugging
|
|
These three systems should be designed together.
|
|
|
|
### Save/Load
|
|
Save files should contain:
|
|
- content hash/version
|
|
- serialized `SimulationState`
|
|
- optional metadata such as timestamp or user-visible slot info
|
|
|
|
### Replay
|
|
Replay files should contain:
|
|
- content hash/version
|
|
- simulation config
|
|
- seed
|
|
- initial start state or entry point
|
|
- action batches per tick
|
|
- optional periodic state checkpoints
|
|
|
|
### Debugging
|
|
A bug report should ideally include:
|
|
- replay file
|
|
- final tick number
|
|
- expected vs actual state hash
|
|
- verification failure artifacts if present
|
|
|
|
This allows deterministic reproduction without stepping through engine code.
|
|
|
|
## Testing Strategy
|
|
Use **xUnit** for all automated simulation tests.
|
|
|
|
Test categories:
|
|
- unit tests for movement, collision, damage, weapons, modifiers, and trigger logic
|
|
- scenario tests for encounters and level scripts
|
|
- replay tests using recorded action streams
|
|
- serialization roundtrip tests for full simulation state
|
|
- desync verification tests for clone-step comparison
|
|
- property or fuzz tests for invariants where useful
|
|
|
|
Coverage expectations:
|
|
- target 100% line and branch coverage for gameplay logic in `SideScrollerGame.Sim`
|
|
- allow narrow exclusions only for generated lookup tables, source-generated serializers, or similar non-logic infrastructure
|
|
- do not use exclusions to hide untested gameplay systems
|
|
|
|
Recommended tooling:
|
|
- xUnit
|
|
- coverlet
|
|
- deterministic test fixtures and builders
|
|
|
|
## Implementation Phases
|
|
### Phase 1: Project Restructure
|
|
- move the Godot project under `/godot`
|
|
- create `src/SideScrollerGame.Sim`
|
|
- create `tests/SideScrollerGame.Sim.Tests`
|
|
- temporarily link the existing root `FixPoint/` sources into the simulation project if needed
|
|
|
|
### Phase 2: Simulation Foundation
|
|
- integrate fixed-point numerics and deterministic RNG
|
|
- define `SimulationState`, snapshots, ids, events, and core step runner
|
|
- define serialization contracts
|
|
|
|
### Phase 3: Replay and Verification
|
|
- define serializable action model
|
|
- implement replay recording and playback
|
|
- implement per-step roundtrip and clone-step verification
|
|
- add debug hashes
|
|
|
|
### Phase 4: Movement and Collision
|
|
- implement actor movement, platforms, ladders, hazards, and projectile sweeps
|
|
- build exhaustive xUnit coverage for collision edge cases
|
|
|
|
### Phase 5: Combat and Behaviors
|
|
- add hero, enemy, weapon, projectile, powerup, and modifier definitions
|
|
- implement behavior graphs, squads, flocking, and boss phase support
|
|
|
|
### Phase 6: Levels and Authoring
|
|
- implement level definitions, triggers, checkpoints, and scripted graph
|
|
- build Godot authoring nodes, validators, and compile/export flow
|
|
|
|
### Phase 7: Presentation Host
|
|
- add interpolation, presenter registry, animation mapping, audio playback, and music director
|
|
- add runtime transport controls and replay inspection UI
|
|
|
|
## Key Decisions to Hold
|
|
- keep all gameplay authority in the pure simulation project
|
|
- keep content definitions in that same project unless a real dependency issue emerges
|
|
- keep the Godot host in its own subfolder and project
|
|
- keep replay, save/load, and verification as first-class features
|
|
- keep fixed-point determinism as the baseline
|
|
- keep the debug transport controls available throughout development
|
|
|
|
If these constraints are maintained, the framework will remain flexible enough for later game design work without collapsing into engine-driven logic or untestable behavior.
|