describeScenes method

  1. @mustCallSuper
void describeScenes(
  1. GameSceneDescriptor descriptor
)

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) {}