diff --git a/README.md b/README.md index 82a9c4b..14ee398 100644 --- a/README.md +++ b/README.md @@ -275,6 +275,23 @@ selects `classic-scumm` as the active theme. Widgets are **not** auto-registered — call `RegisterDefaultUI(g)` (or one of its siblings) explicitly, or let `Run` install the default set if `UIManager` is empty. +The manager fields are ordinary `*Manager` values, so a domain that keeps its +own registries can **assign them onto the Game** instead of copying every entry +across: + +```go +g := inkwell.NewGame("Real World", 640, 380) +g.SceneManager = mySceneManager +g.AssetManager = myAssetManager +``` + +Do it before `Run` — that is where the engine wires up the parts that hold a +registry directly, so whichever managers the `*Game` carries by then are the +ones that get used. Two of them are worth a second thought before replacing: +`ThemeManager` arrives holding the four presets and `classic-scumm` selected, +and `VerbManager` the four SCUMM verbs. Replacing either throws that away — +register into them instead unless that is what you want. + ### 4.2 Lifecycle hooks ```go @@ -1517,13 +1534,15 @@ func Run(g *Game) error // toplevel — same as g.Run() `Run` does, in order: -1. `g.Validate()` — cross-check name references between managers. -2. If `UIManager` is empty, call `RegisterDefaultUI(g)`. -3. Place the start scene directly (no transition), bump +1. `g.Audio.attach(g.AssetManager)` — wire the audio player to whichever + asset registry the game is carrying by now. +2. `g.Validate()` — cross-check name references between managers. +3. If `UIManager` is empty, call `RegisterDefaultUI(g)`. +4. Place the start scene directly (no transition), bump `State.NoteVisit`, position registered actors, kick off music. -4. Compose `Seq(scene.OnEnter, game.OnStart)` and queue it as the initial +5. Compose `Seq(scene.OnEnter, game.OnStart)` and queue it as the initial action — the first script tick runs both in order. -5. `ebiten.SetWindowSize(Width*4, Height*4)`, +6. `ebiten.SetWindowSize(Width*4, Height*4)`, `ebiten.SetWindowTitle(g.Title)`, then `ebiten.RunGame(&engine{g})`. ### 15.1 `engine.Update` diff --git a/core.dsl.go b/core.dsl.go index 256465f..29a1cf0 100644 --- a/core.dsl.go +++ b/core.dsl.go @@ -7,6 +7,10 @@ import ( // Run validates the game, then enters the ebiten main loop. The window is // sized to 4× the internal resolution. func Run(g *Game) error { + // The domain may have swapped a manager in since NewGame, so the parts + // that hold a registry directly are wired here, not at construction. + g.Audio.attach(g.AssetManager) + if err := g.Validate(); err != nil { return err } diff --git a/core.game.go b/core.game.go index d23277d..8e1bd9b 100644 --- a/core.game.go +++ b/core.game.go @@ -114,6 +114,10 @@ type runtimeDialog struct { // NewGame initializes a game with empty entity managers, the SCUMM-style // verb set, all preset themes, and "classic-scumm" selected. Widgets are // NOT auto-registered — call RegisterDefaultUI(g) explicitly. +// +// A domain is free to replace any of the entity managers with one of its +// own before Run — the registries are ordinary *Manager values, and Run +// wires the engine to whichever ones the Game holds by then. func NewGame(title string, w, h int) *Game { g := &Game{ Title: title, @@ -138,7 +142,6 @@ func NewGame(title string, w, h int) *Game { transition: &transition{}, selectedVerb: "look", } - g.Audio.attach(g.AssetManager) for _, v := range defaultVerbs() { g.VerbManager.Register(v) }