Scene・状態・UI

Canvas UI・Flex・Pointerも利用できます。このページは引き続きネイティブDOM UIを扱います。

ゲームのルールとDOM表示を分け、型付きScene IDで画面を移動します。メニューとプレイの状態はゲーム側で定義します。

Sceneを登録する

import {
  Button,
  Character,
  Game,
  Label,
  Action,
  ActionController,
  defineActions,
  KeyboardBindings,
  Panel,
} from "@simpludify/web";

const game = new Game<"menu" | "play">();
const Actions = defineActions({ Move: Action.axis2D() });
game.scene("menu", ({ ui }) => {
  ui(Panel([Label("Ready?"), Button("Start", () => game.goTo("play"))]));
});
game.scene("play", ({ scene, add, ui }) => {
  const controls = new ActionController(Actions, {
    scene,
    input: game.engine.input,
    bindings: { Move: KeyboardBindings.WASD },
  });
  add(Character({ movement: controls.reader(Actions.Move) }));
  ui(Panel([Button("Menu", () => game.goTo("menu"))]));
});
await game.run("menu");

runをawaitしてからgoToします。準備の間は旧Sceneが動き続け、準備失敗なら旧Sceneを保ちます。成功した切り替えで旧Sceneは破棄されます。同じIDへ完了後に遷移しても新しいインスタンスを作るので、再プレイにも使えます。

非同期準備とキャンセル

setupはPromiseを返せます。contextのsignalをロードへ渡し、await前にonDisposeへ片付けを登録します。SceneやGameの破棄は保留遷移をキャンセルしますが、任意のPromiseを強制停止することはできません。

CoreのScene状態はPreparing → Ready → Active → Inactive → Disposedです。Webはアセット準備と表示の整合性を担当します。WebのScene factoryからEngine.activateやmarkReadyを直接操作しないでください。

状態をUIへ反映する

Label.setTextは値が変わったときだけ表示を更新します。ゲーム側モデルを通常のコードで読み取るか、変更イベントから反映します。

const score = Label("Score 0");
scene.events.on(
  ScoreChanged,
  (state) => {
    score.setText(`Score ${state.score}`);
  },
  scene,
);
ui(Panel([score]));

Signal RunのRoundはHP・スコア・残り時間・勝敗をCoreだけで扱い、WebのSceneがラベルと遷移へ結び付けます。全状態を自動シリアライズするストアはありません。

レイアウトと操作

PanelはColumnが既定、Layout.Rowは折り返し、Gridは自動配置します。Placement.Top / Center / Bottom、Theme.Dark / Light、部分的なtokensを選べます。DOM UIはCameraのzoomに影響されません。

Buttonはネイティブ要素でTab・Enter/Spaceに対応します。同期handlerではフォーカスを保ちます。非同期handler実行中はaria-disabled/aria-busyと重複実行ガードで再操作を抑止し、Tab対象から外します。現在のフォーカスを不必要に失わず、WASD等の未消費ゲームキーを継続できます。失敗は診断へ渡します。handlerへ渡るAbortSignalはUI破棄で中断されます。固定CSS配置は独自にクリッピングを検証してください。

所有権とエラー

購読・タイマー・ActionSourceはScene/Actor/Componentへ所有させます。独自DOMリスナーはsetupのsignal、または明示的なcleanupを使います。破棄は冪等で、あるcleanupが失敗しても他を実行します。

切り替えの準備前エラーは旧Sceneを維持しますが、コミット後のライフサイクル通知エラーは新Sceneを巻き戻しません。更新中の変更も自動ロールバックしません。詳細は英語のArchitectureに記載しています。