ゲーム開発

【Unity】どのシーンから起動しても共通の初期化を呼び出したい

Unityエディタって優秀ですよね。
プレイボタンを押せば、編集中のシーンをいつでも実行できるのは魅力的です。
しかし、ゲームを作ってると、最初に共通の初期化を行いたいケースってあると思います。
C++ではmain関数をエントリに処理されますが、Unityではどうでしょう?

この方法が使えます。

Unity - Scripting API: RuntimeInitializeOnLoadMethodAttribute
[RuntimeInitializeOnLoadMethod]

このAttributeが指定されたメソッドは、ゲームがロードされた直後に呼び出されます。
この特徴を利用して、InitializeScene.unity と、Initialize.cs を用意します。
(名前は分かりやすければ何でもOKです)

using UnityEngine;
using UnityEngine.SceneManagement;

public class Initialize
{
    private const string InitializeSceneName = "InitializeScene";
    
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    public static void RuntimeInitializeApplication()
    {
        Debug.Log("RuntimeInitializeApplication");
        
        if (!SceneManager.GetSceneByName(InitializeSceneName).IsValid())
        {
            SceneManager.LoadScene(InitializeSceneName, LoadSceneMode.Additive);
        }
    }
}

このスクリプトはGameObjectにアタッチする必要はありません。
ゲームを再生すると、カレントシーンにInitializeSceneを追加ロードします。
どのシーンから起動してもInitializeSceneは必ず追加ロードされるので、このシーンに初期化用のGameObjectを置いてスクリプトを付けておけば、共通の初期化を呼び出せます。

GameObjectが DontDestroyOnLoad なシングルトンであれば、グローバルなマネージャクラスを作ることもできます。デバッグ用のマネージャクラスなど、どのシーンから起動しても処理したいものはInitializeScene に置いて運用すると大変便利です。

ただし、気を付けなければならい点が2つあります。

1つ目はInitializeSceneは、SceneInBuildの最後に配置しておく必要があること。
2つ目は処理の流れです。

  1. RuntimeInitializeApplicationが呼び出される
  2. 現在のシーンのオブジェクトのAwakeが呼び出される
  3. InitlizeシーンのオブジェクトのAwakeが呼び出される
  4. 現在のシーンのオブジェクトのStartが呼び出される
  5. InitlizeシーンのオブジェクトのStartが呼び出される

現在のシーンのオブジェクトが先に処理される点に注意してください。
AwakeやStartに書く処理がInitializeSceneのオブジェクトに依存しないように設計しましょう。

例えば、2の時点ではSimpleSoundManagerは存在しないので、参照してはいけません。
もしStart時にBGMを再生したい場合は4でコルーチンを起動し、WaitForEndOfFrameしてからSimpleSoundManager.Instanceでアクセスして処理すると良いでしょう。

タイトルとURLをコピーしました