Bootstrap

フレームワークの自動起動 — 最初のシーンがロードされる前に、23 のサービスすべてを依存順に登録します。

フレームワークの自動起動 · 最初のシーンがロードされる前に一度だけ実行 · 23 のサービスすべてを登録 · 差し替え不可

概要

Bootstrap はフレームワークの自動起動ルーチンです。23 のサービスすべてを依存順に登録し、前回の Play セッションから残った内部 GameObject を削除し(エディタで Domain Reload が無効な場合にのみ関係します)、Logger をウォームアップします。あなたがこれを呼び出すことはありません — Unity が最初のシーンのロード前に自動で呼び出し、Play セッションごとにちょうど一度だけ実行されます。

起動が完了すると、Unity Console に次の行が表示されます:

bootstrap complete (v2.1.0, 23 services)

この行が表示されていれば、フレームワークは起動済みで、すべてのサービスが使用可能です。

簡単な使用例

実際の使い方として最も一般的なのは、Bootstrap を直接呼び出すことは決してないという点です。自分の Awake が実行される頃には、すべてのサービスはすでに登録済みです — 解決(resolve)して使うだけです。

using CommonGameSystem.Core;
using UnityEngine;

[DefaultExecutionOrder(100)]  // Run AFTER framework startup — the attribute goes on the class
public class GameController : MonoBehaviour
{
    void Awake()
    {
        // Bootstrap.Run has already fired. All services are registered.
        // Resolve once and cache the references.
        var time = ServiceLocator.Resolve<ITimeService>();
        var pool = ServiceLocator.Resolve<IObjectPoolService>();
        var bus  = ServiceLocator.Resolve<IEventBus>();

        // DeltaTime is a method: you pick the clock you want.
        Debug.Log($"Gameplay: {time.DeltaTime(Clock.Gameplay)}, " +
                  $"unscaled: {time.UnscaledDeltaTime(Clock.Gameplay)}");
    }
}

EditMode テストでは、Bootstrap は通常すでに実行されています — 起動フックはテストドメインでも発火します — ので、サービスをそのまま解決できます:

using CommonGameSystem.Core;
using NUnit.Framework;

public class BootstrapSmokeTests
{
    [Test]
    public void Bootstrap_RegistersCoreServices()
    {
        // Bootstrap.Run already fired for the test domain. Resolve and assert.
        Assert.IsNotNull(ServiceLocator.Resolve<ILogger>());
        Assert.IsNotNull(ServiceLocator.Resolve<IObjectPoolService>());
        Assert.IsTrue(Bootstrap.HasRun);
    }
}

API の全体像

解決すべきものはありません。Bootstrap は Unity の [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] フックによって自動的に発火します。あらゆるシーンの Awake より前、あなたのコードが Service Locator に触れるより前に実行されます。

namespace CommonGameSystem.Core
{
    public static class Bootstrap
    {
        // Entry point — Unity calls this automatically (do NOT invoke directly).
        public static void Run();

        // Registers the settings-persistence backend. Public so automated
        // tests can inject a stub; not part of normal use.
        public static void RegisterConfigurationPersistence();

        // Diagnostic-only (read-only — set internally). Editor-only:
        // these two properties do not exist in player builds.
        public static bool HasRun { get; }
        public static int  RunCount { get; }
    }
}
メンバー説明
Run()起動のエントリーポイント。Unity が Play セッションごとに一度、最初のシーンのロード前に呼び出します。自分でもう一度呼び出すと ServiceAlreadyRegisteredException がスローされます。
RegisterConfigurationPersistence()Configuration サービスが設定の保存に使うストレージバックエンドを登録します: Save/Load サービスがアクティブならそれを、そうでなければ Unity の PlayerPrefs を使います。テストがフォールバックを検証できるようにするためだけに public になっています。通常の使用では呼び出しません。
HasRun起動が少なくとも一度完了していれば true。読み取り専用で、エディタ専用 — 参照は #if UNITY_EDITOR で囲むか、Editor/テストアセンブリの中に留めてください。
RunCount起動実行回数の累計(エディタで Domain Reload が無効の場合、Play セッションをまたいで増えていきます)。読み取り専用、エディタ専用

登録順に見る 23 のサービス

Bootstrap は以下のサービスを、この順序で起動します。それぞれ ServiceLocator.Resolve<T>() で解決するインターフェースで、専用のリファレンスページがあります。

  1. ServiceLocator — 他のすべてのサービスが登録されるレジストリで、任意のサービスを取得するために呼び出す唯一のクラス。Service Locator を参照。
  2. ILogger — カテゴリ別フィルターを備えたカテゴリ化ロギング。Logger を参照。
  3. IObjectPoolService — プレハブのプーリング。Object Pool を参照。
  4. ITimeService — クロックごとの時間・ポーズ・スローモーション(Gameplay/UI/Background クロック)。Time を参照。
  5. IEventBus — システム間の型安全な publish/subscribe。Event Bus を参照。
  6. ISaveService — 安全なアトミック書き込みとスロットを備えた JSON セーブファイル。Save/Load を参照。
  7. IConfiguration — 変更イベント付きの型付き設定グループ。Configuration を参照。
  8. IInputService — 入力アクションマップのコンテキストとキーリバインド。Input を参照。
  9. IAudioService — AudioMixer を介した音楽・効果音・ボイス。Audio を参照。
  10. IPanelStack — ゲームパッドとキーボードのフォーカスに対応した UI パネルの push/pop。UI Framework を参照。
  11. ISceneService — ローディング画面・キャンセル対応・加算ロード/アンロードを備えた非同期シーンロード。Scene Flow を参照。
  12. ILocalizationService — キーから文字列への検索と実行時の言語切り替え。Localization を参照。
  13. IAchievementService — 自動アンロック付きのローカル統計と実績。Achievements を参照。
  14. IScheduler — After/Every/NextFrame タイマーとメインスレッド実行ディスパッチ。Scheduler を参照。
  15. ITweenService — 31 種類のイージングを備えたポーズ対応の値トゥイーン。Tween を参照。
  16. IAssetProvider — 参照カウント付きの Addressables ロード。Asset Provider を参照。
  17. IRandomService — 名前付きストリームを備えた、シード指定で再現可能な乱数。Random を参照。
  18. IStateMachineService — フラットな有限ステートマシンのファクトリ。FSM を参照。
  19. IPushdownStackService — スタック化されたゲームステートのスコープ(ゲームプレイの上にポーズメニュー、など)。Pushdown Stack を参照。
  20. ITweenSequenceService — 順次実行・並列実行のトゥイーンタイムライン。Tween Sequencing を参照。
  21. IAddressableSceneService — Addressables からロードする加算シーン。Addressable Scene を参照。
  22. IDeferredBus — イベントを今キューに積み、後でフラッシュ。Deferred Event Queue を参照。
  23. ICommandRegistry — ランタイムコマンドレジストリ(コンソール UI は自作します)。Command Registry を参照。

内部ヘルパーの登録

Bootstrap は、自動テストが差し替えられるように、いくつかの内部ヘルパーも登録します: 設定永続化バックエンド、3 つの組み込み設定バリデーター、入力キーマップソースです。ゲームコードがこれらを直接解決することはなく、23 サービスの数にも含まれていません。

挙動とエッジケース

  • 一度だけ実行されます。 1 つの Play セッション内で Bootstrap.Run() を 2 回呼ぶと ServiceAlreadyRegisteredException がスローされます。Unity のフックが Play 開始ごとにちょうど一度の発火を保証するため、自分で呼ぶ必要は一切ありません。

  • メインスレッド専用。 起動フックは Unity のメインスレッドで実行されます。Debug ビルドはこれをアサートし、違反は早期に検出されて Play が中断されます。

  • 登録前のクリーンアップ。 サービスを登録する前に、Bootstrap は前回の Play セッションから残ったフレームワーク内部の GameObject を削除します。これが意味を持つのは、エディタで Domain Reload が無効なとき(Project Settings → Editor → "Enter Play Mode Settings")だけです。Domain Reload が有効なら、各 Play セッションはそもそもクリーンなヒエラルキーで始まります。フレームワークは内部のマーカーコンポーネントで自身の残存オブジェクトを見つけ、Object.Destroy で破棄します — 即時ではなくフレーム終了時の破棄なので、PlayMode テストでは起動後に yield return null して破棄を確定させてください。マーカーコンポーネントはフレームワーク内部用です。自分でアタッチしないでください。

  • Logger のウォームアップ。 起動中、Bootstrap はメインスレッドで Logger を一度呼び出します。この呼び出しが static な Logger ヘルパーを準備し、以降のワーカースレッドからの呼び出し(たとえばセーブファイルの I/O)を安全にします。

  • 起動の失敗は Play を停止します。 シーケンスの後半で生成されるサービスは、依存関係をコンストラクター経由で受け取ります。コンストラクターがスローすると例外は伝播し、Play は即座に中断されます — 問題は数分後ではなく、起動時に表面化します。

  • エディタのシャットダウンフック。 エディタでのみ、Bootstrap は Play モードの終了を監視し、破棄可能なすべてのサービスを登録の逆順で破棄します。プレイヤービルドにこのフックは含まれません — 通常のプロセス終了処理に任せます。

  • Bootstrap 自体は差し替えできません — 他のすべてを起動するコードそのものだからです。ただし、登録される各サービスは差し替え可能で、どのサービスにも 1 行でオフにできる Null(no-op)実装が付属しています:

    // Example: silence all diagnostics
    ServiceLocator.Replace<ILogger>(new NullLogger());
    
    // Example: disable audio entirely
    ServiceLocator.Replace<IAudioService>(new NullAudio());
    
    // Example: stub the scene service for testing
    ServiceLocator.Replace<ISceneService>(new NullSceneService());
    

    Logger には 1 つ注意点があります: static な Logger ヘルパーは起動時にバックエンドをキャッシュするため、セッション途中で差し替えてもリターゲットされません。実行時にロギングをミュートするには、代わりに Logger.MinimumLevel = LogLevel.Off を設定してください — 詳細は Logger を参照。

関連ページ