Systems
A system is a static method with the signature void SystemName(World world). It queries for entities with specific components and acts on them.
Built-in Systems
All built-in systems live in game_logic/systems/ (one file per system, using a partial class Systems pattern).
InputMovementSystem
Queries: Movable + Transform + Rigidbody
Physics-based character movement system:
W / A / S / Ddrives horizontal velocity- Movement is camera-relative when a
Cameracomponent is attached to the same entity SPACEapplies jump vertical velocity (edge-detected, grounded check)- Player visual rotation faces movement direction
- Disabled when free camera is active — returns early so WASD controls only the free camera
TimerSystem
Queries: Timer
Ticks all Timer components each frame using world.DeltaTime:
- One-shot timers (
Repeat = false):Finishedis set totrueonce and the timer stops advancing - Interval timers (
Repeat = true):Finishedis set totrueeach cycle, andElapsedwraps by subtractingDuration
PhysicsSystem
Queries: Rigidbody + Collider + Transform
Three-phase system that integrates Jolt Physics:
- Create bodies — For entities with
Rigidbody+Collider+Transformwhere_BodyCreatedisfalse, creates the Jolt shape and body. - Step physics — Advances the Jolt simulation via
PhysicsWorld.Instance.Step()using a fixed 1/60s timestep accumulator. - Sync transforms — Reads position and rotation back from Jolt for dynamic bodies and writes them to the ECS
Transformcomponent (quaternion converted to Euler degrees).
Static bodies are created but not synced back (they don't move).
FreeCameraSystem
No query — uses static FreeCameraState.
A debug fly camera for inspecting the scene freely. Only activates when GameConstants.Debug is true. Press 0 to activate, 1 to deactivate.
When active:
- WASD — fly forward/back/strafe left/right
- Q/E — fly down/up
- Mouse — look around (when cursor is locked)
- ESC — toggle cursor lock
Sensitivity and speed come from GameConstants.FreeCamSensitivity and GameConstants.FreeCamSpeed. Overrides the camera directly via NativeBridge.SetCamera(). Both InputMovementSystem and CameraFollowSystem return early when the free camera is active.
CameraFollowSystem
Queries: Camera + Transform
Disabled when the free camera is active — returns early.
Handles both camera modes:
- Third-person (
CameraMode.ThirdPerson): Orbits the camera around the entity. Scroll wheel zooms in/out, clamped betweenMinDistanceandMaxDistance. - First-person (
CameraMode.FirstPerson): Places the camera at entity position +EyeHeight, looking along yaw/pitch direction.
Controls:
- Q/E — yaw (horizontal orbit)
- R/F — pitch (vertical orbit)
- Mouse — free-look when cursor is locked
- Scroll wheel — zoom (third-person only)
- TAB — toggle first-person / third-person (edge-detected)
- ESC — toggle cursor lock on/off
HierarchyTransformSystem
Queries: Transform
Computes world-space transforms for entities in a parent-child hierarchy:
- For child entities (with
Hierarchycomponent pointing to a valid parent), walks the parent chain and multipliesparent.WorldTransform * child.LocalTransform - Automatically adds a
WorldTransformcomponent to child entities if not present - Root entities keep their local transform as-is
LightSyncSystem
Queries: Light + Transform
Pushes light data to the C++ renderer each frame. Supports up to 8 active lights. Automatically assigns light slots and clears unused ones.
DebugOverlaySystem
No query — reads key state and calls NativeBridge.SetDebugOverlay().
Toggles the debug overlay on/off when the F3 key is pressed (edge-detected). Each press flips GameConstants.Debug and syncs the state to the C++ renderer. See Debug Overlay for details on what the overlay displays.
DebugColliderRenderSystem
Queries: Collider + Transform
Creates and syncs wireframe debug entities that visualize physics collider shapes. Only active when GameConstants.Debug is true. Wireframe color is determined by each collider's DebugColor field (defaults to green).
- When debug is enabled, creates a wireframe mesh matching each collider's shape and
DebugColor(box, sphere, capsule, cylinder — planes are skipped) and registers it as a debug renderer entity - Each frame, updates the debug entity transforms to match the collider's current position and rotation
- When debug is disabled, calls
NativeBridge.ClearDebugEntities()and clears tracking state - Automatically removes debug entities for despawned ECS entities
Debug entities use a separate renderer pipeline (VK_POLYGON_MODE_LINE) and are only drawn when the debug overlay is active. See Debug Overlay for full details.
RenderSyncSystem
Queries: Transform + MeshComponent
Pushes transform matrices to the C++ renderer for each entity with a mesh. Uses WorldTransform.Matrix if available (for entities in a hierarchy), falling back to Transform.ToMatrix() for root entities. This should always be the last system so it sees the final state of all transforms.
Registration Order
Systems run in the order they are added. Order matters. Systems are registered in game_logic/Game.cs inside the Game.Setup(world) method:
FreeCameraSystem is optional. If you enable it, register it before CameraFollowSystem.
Writing Custom Systems
Register them in game_logic/Game.cs before RenderSyncSystem:
RenderSyncSystem should always be the last system so it sees the final state of all transforms for the current frame.