describeScenes method
Declares every SceneStruct this game can load.
late final MainScene mainScene;
late final HudScene hudScene;
@override
void describeScenes(GameSceneDescriptor descriptor) {
super.describeScenes(descriptor);
mainScene = descriptor.has(MainScene());
hudScene = descriptor.has(HudScene());
}
Like every other declare pass this hands back the instance it was given,
to keep in a late final field (the typed-handle rule) - there is no
separate handle type, and descriptor.has(MainScene()) reads the same as
descriptor.has(MySystem()) and descriptor.has(_Unit()) because it is
the same idea.
What declaring buys, and what it does not
Declaring a scene here registers its archetypes and declares its
assets, at boot - before the game isolate is spawned, and before any
system's describeQuery runs (which is why this pass comes first).
GameState.loadScene(game.mainScene) then costs no registration at all:
it allocates rows and mounts.
That matters because registration is the half of loading that cannot
happen freely at runtime - archetype ids are process-global and never
recycled, so a scene registered afresh on every load would leak ids and
leave every unloaded scene's archetypes in the registry for queries to
keep walking. Declaring once and loading many times is what lets several
instances of one SceneStruct be resident at the same time.
A SceneStruct is a declaration, not a per-instance object - the
same relationship EntityStruct has to Entity. Prefab fields on it are
fine; mutable per-instance state is not, because every loaded Scene
built from it shares this one object. Per-instance state belongs in
components.
Passing an undeclared scene to loadScene still works and still
registers lazily, so this pass is additive rather than a new obligation.
Implementation
@mustCallSuper
void describeScenes(GameSceneDescriptor descriptor) {}