シーン
Turian シーンは、ノードツリーとしてインスタンス化できます(Godot シーンや Unity プレハブのように)。シーンマネージャーが残りの半分を提供します——Unity の SceneManager のように、シーンを名前付きのアドレス可能なユニットとして扱い、ロードおよびアンロードを一括で行い、アドバティブシーン、永続オブジェクト、非同期ロード、ライフサイクルイベントをサポートします。
ブートシーンはプロジェクト設定(first_scene)から取得されます。そこから、ゲームは engine.SceneManager サービスを通じてシーン遷移を制御します。
スクリプトからマネージャーにアクセスする
マネージャーはサービスとして注入され、任意のコンポーネントの Frame からアクセスできます:
const engine = @import("engine");
pub const SceneDirector = struct {
pub const is_component = true;
// インスペクターで設定。ハードコードではありません——「フィールドとしてのシーン参照」を参照
level_a: engine.TypedAssetRef(.scene) = .{},
level_b: engine.TypedAssetRef(.scene) = .{},
pub fn start(self: *SceneDirector, frame: engine.Frame) void {
const mgr = frame.service(engine.SceneManager) orelse return;
// ブートストラップシーン(カメラ/ディレクター)をレベル切り替え間で生存させる
if (mgr.getActiveScene()) |boot| mgr.setScenePersistent(boot, true);
mgr.requestLoad(self.level_a.guid(), .additive);
}
pub fn update(self: *SceneDirector, frame: engine.Frame) void {
const mgr = frame.service(engine.SceneManager) orelse return;
if (frame.input.wasKeyPressed(.num_2)) mgr.requestLoad(self.level_b.guid(), .single);
}
};
フィールドとしてのシーン参照
シーン GUID をコードに直接貼り付ける代わりに、engine.TypedAssetRef(.scene) フィールドを宣言します。インスペクターはそれに対してシーンアセットピッカーを表示します(アセットブラウザからシーンをドラッグするか、... ボタンを使用してシーンにフィルタリングされたリストから選択します)。選択された GUID はシーンファイルに保存され、ランタイムでフィールドに復元されるため、スクリプトは field.guid() で読み取ります:
next_scene: engine.TypedAssetRef(.scene) = .{},
pub fn update(self: *@This(), frame: engine.Frame) void {
const mgr = frame.service(engine.SceneManager) orelse return;
if (frame.input.wasKeyPressed(.space))
mgr.requestLoad(self.next_scene.guid(), .single);
}
これはメッシュやマテリアルに使用されるものと同じ型付きアセット参照メカニズムで、シーン向けに特化したものです——デザイナーはコードに触れずに遷移を設定できます。
ロードモード
| モード | 動作 |
|---|---|
.single |
非永続のすべてのシーンをアンロードしてから新しいシーンをロード——古典的な「次のレベル」遷移。 |
.additive |
既にロードされているシーンに加えて新しいシーンをロード。 |
永続シーン(DontDestroyOnLoad)
mgr.setScenePersistent(handle, true) はシーンを .single ロードでも生存させるようにマークします。カメラ、HUD、コントローラーを永続的なブートストラップシーンに配置すると、すべてのレベル遷移後もそれらは存続します——Unity の DontDestroyOnLoad に相当するシーンマネージャーの機能です。(個々のノードも markDontDestroyOnLoad を使用して専用の永続シーンに移動できます。)
遅延リクエスト
スクリプトは requestLoad / requestUnload でシーン変更を要求します。これらはフレームの終わりに適用され、更新の途中で適用されることはありません——そのためスクリプトは自分が実行されているシーン自体を安全にアンロードできます。(loadScene / unloadScene は即時、ホスト側制御用としても利用可能です。)
追跡とクエリ
const active = mgr.getActiveScene(); // ?SceneHandle
var buf: [engine.SCENE_MANAGER_MAX_SCENES]engine.SceneHandle = undefined;
const loaded = mgr.getLoadedScenes(&buf); // []SceneHandle
const here = mgr.findById(LEVEL_A); // ?SceneHandle
const ok = mgr.isLoaded(handle);
ライフサイクルイベント
シーンの状態変更時に通知を受け取るには購読します:
mgr.subscribe(onSceneEvent, ctx); // loaded / unloaded / activated / deactivated を発火
非同期ロード
大きなシーンはワーカースレッドでロードでき、フレームをブロックしません:
const h = try mgr.loadSceneAsync(io, id, .single);
// ... ローディング画面をレンダリングし続ける ...
if (mgr.isReady(h)) _ = mgr.finishAsync(io, h, .single);
エラーハンドリング
同期ロードは型付きエラー(NoLoader、LoadFailed、TooManyScenes)を返します。非同期ロードの場合は mgr.getError(handle) でシーンごとの理由を取得できます。
例
リポジトリの examples/scene-management/ にある、ブート + 永続ブートストラップ + アドバティブロード + ランタイム切り替えの完全な実行可能デモを参照してください。