| name | extending-the-engine |
| description | Step-by-step recipes for adding new game objects, shaders, models, player-selectable aircraft, scenes, or renderers to the ToyFlightSimulator engine. Use when creating a new GameObject/Aircraft subclass, a Metal shader plus its pipeline state, a model file registration, an AircraftType case, a GameScene subclass, or a Renderer subclass. |
Extending the engine
Registration recipes for the ToyFlightSimulator Metal engine. Each list is the full set of
touchpoints — missing one typically compiles but silently does nothing at runtime.
Adding New Game Objects
- Extend
GameObject (or Aircraft for vehicles)
- Override
doUpdate() for per-frame logic
- Add to scene via
addChild() in a GameScene.buildScene() override
- SceneManager auto-registers for batched rendering (base
objectType handles opaque/transparent/tessellatable; override it — and extend GameObjectType + both add/remove switches — only for a new side collection)
- For physics: construct a
SphereRigidBody/PlaneRigidBody (self-attaches to the GameObject) and register it with the scene's PhysicsWorld via addEntity()
- Runtime despawns must use
removeFromScene(), not bare parent?.removeChild(self) (see Scene Graph in CLAUDE.md)
Adding New Shaders
- Add Metal functions to appropriate .metal file (or new file)
- Add enum case to
RenderPipelineStateType
- Create pipeline state struct in relevant pipeline library file
- Register in
RenderPipelineStateLibrary.makeLibrary()
- Use in renderer via
setRenderPipelineState(encoder, state: .NewType) (convenience sugar over the raw encoder bind) and pass the stage's pipeline type to the mesh-draw entry points — DrawManager.DrawOpaque/DrawTransparent/DrawShadows take psoType:, from which SetupAnimation derives the skinned-mesh animated PSO via animatedVariant and restores the pass PSO at non-skinned meshes and loop boundaries (no global pipeline tracking; keep the bind and the draw call reading one local constant)
Adding New Models
- Place model files in
Core/Resources/Models/
- Add
ModelType enum case in ModelLibrary
- Register a factory in
ModelLibrary.makeLibrary(): register(.NewModel) { ObjModel("name") } or { UsdModel("name", fileExtension: .USDZ) } (built lazily on first access)
- Access via
Assets.Models[.NewModel]
Adding New Player-Selectable Aircraft
- Add the
AircraftType case (rawValue is the display name in the picker)
- Handle it in
FlightboxWithPhysics.applyAircraftSwap's switch (construct the Aircraft subclass)
- Add its
AircraftThumbnailSpec.spec(for:) entry — model name/extension must mirror ModelLibrary.makeLibrary(); tune the uprighting rotations visually and bump ThumbnailCameraConfig.specVersion when changing pose constants
- Override
cameraOffset on the Aircraft subclass if the default [0, 10, -20] doesn't frame it well
Adding New Scenes
- Create
GameScene subclass
- Override
buildScene() to add objects, cameras, lights
- Add
SceneType enum case
- Register in
SceneManager.SetScene() switch
Adding New Renderers
- Create renderer class extending
Renderer
- Conform to needed protocols (
ShadowRendering, ParticleRendering, TiledGBufferRendering, LateDrawablePresenting, etc.)
- Add
RendererType enum case
- Register in
Engine.InitRenderer() switch