LoginSignup
15
12

More than 3 years have passed since last update.

ZenjectSceneLoaderでシーン間のパラメータ渡しをシンプルに実現する

Last updated at Posted at 2018-10-10

はじめに

この記事ではゲームエンジン Unityにおいて、シーンを遷移させる時にパラメータを渡す方法として、 ZenjectSceneLoader を利用した方法を紹介していきます。

本記事ではZenject ver 7.3.0をターゲットバージョンとしています。(6.x 以下での動作はわかりません)

この記事を3行にまとめると…

  • ZenjectSceneLoaderを使うと現在のシーン上から遷移後のSceneContextに任意のパラメータをBindできる
  • 遷移後のシーンで稼働するBehaviour内でパラメータをInjectして利用する
  • ProjectContextやDecoratorContextを使わなくてもシーン遷移時パラメータ渡しが出来る!

ZenjectSceneLoaderとは

ZenjectSceneLoaderの主な機能(シーン読み込み時の追加的なBindやSceneContextの親子関係の制御)については
ZenjectSceneLoaderのLoadSceneのオーバーロードメソッドの引数に注目して読むことで見えてくるかと思います。


public AsyncOperation LoadSceneAsync(string sceneName)

public AsyncOperation LoadSceneAsync(string sceneName, LoadSceneMode loadMode)

public AsyncOperation LoadSceneAsync(
    string sceneName, LoadSceneMode loadMode, Action<DiContainer> extraBindings)

public AsyncOperation LoadSceneAsync(
    string sceneName,
    LoadSceneMode loadMode,
    Action<DiContainer> extraBindings,
    LoadSceneRelationship containerMode)

public AsyncOperation LoadSceneAsync(
    string sceneName,
    LoadSceneMode loadMode,
    Action<DiContainer> extraBindings,
    LoadSceneRelationship containerMode,
    Action<DiContainer> extraBindingsLate)

UnityスタンダードのSceneLoader.LoadSceneには見られない引数として…

  • extraBindings
  • containerMode
  • extraBindingsLate

の3つがあります。

1つ目と3つ目に出てきた extraBindingsとextraBindingsLateは遷移後のシーンに置かれたSceneContextのInstallメソッド内で呼び出される、追加のBindingを設定できるActionです。

extraBindingsのAction内からDiContainer.BindInstance等でパラメータを設定するようにします。例えばゲームリザルトの情報などをここで設定すれば、遷移先シーンのライフタイムに限定した状態でパラメータを渡す形が作れるわけです。

ただし、遷移後のシーンにSceneContextが存在しない場合は何も起きません。注意しましょう。

SceneContextがextraBindingsを解決するまでの内部的な挙動について

まずLoadSceneが呼び出された直後のシーン遷移前にSceneContextのstatic変数として定義されたExtraBindingsInstallMethod へとextraBindingsを配置する下準備が行なわれます。
次にシーン遷移後に移って、遷移後のシーンに配置されたSceneContextがAwakeされるタイミングでInstallメソッドが呼ばれます。
そのInstallメソッド内でExtraBindingsInstallMethodが遷移後のシーンのSceneContext上で呼び出される、という流れになっています。

さらに詳しくは ZenjectSceneLoader やZenjectリポジトリ内からExtraBindingsInstallMethodで検索してみてください。

また、LoadSceneで見慣れない引数として LoadSceneRelationship もありますね。こちらはそのソースに書かれたコメントがそのまま説明になるかと思います。

LoadSceneRelationship.Noneを指定した場合はProjectContextを親コンテナに配置します。(default値です)

LoadSceneRelationship.Child を指定した場合には現在のシーンのSceneContextの子として配置できます。(ただ、この場合は LoadSceneMode.Additive を指定する必要がある? )

LoadSceneRelationship.Siblingは遷移前のシーンの親を次のシーンの親とする設定です。多くの場合はNoneとほぼ同義、とのことです。

最後に、extraBindingsLateについてです。LateとあるようにSceneContextのインスペクター経由で設定できるInstallers等を実行した後に実行されます。

実用例が思い浮かばないですが、インスペクター経由でSceneContextに設定できるInstallersなどが解決された後に実行したいBindがあればextraBindingsLateを利用するとよさそうです。

BindやInstallerの解決順については SceneContext のInstallBindings メソッドを確認してみてください。

さて、次に具体的なコードで説明してみたいと思います。
以下は、ZenjectSceneLoader.LoadSceneAsync の extraBindings引数 を使ってパラメータを一個だけに限定してDiContainerにBindを仕掛けるコードの例です。


public class MySceneManager : IMySceneManager
{
    [Inject]
    ZenjectSceneLoader sceneLoader;

    public void TransitionScene<T>(string targetSceneName, T sceneParameter)
    {
        Debug.Log("Load scene: " + targetSceneName);

        sceneLoader.LoadScene("Scenes/" + targetSceneName, LoadSceneMode.Single, 
            (diContainer) => 
            {
                if (sceneParameter != null)
                {
                    diContainer.BindInstance(sceneParameter).AsTransient();
                }
            });

        Debug.Log("Load scene done");
    }

TransitionSceneメソッドのsceneParameterで指定した一つの値をextraBindingsのActionからDiContainerにBindしています。containerModeは指定していないのでNoneが設定される、ということになりますね。

上記のシーン間パラメータとして宣言しているテンプレート型 T は、非同期で使うことも考えるとイベントで扱うのと同様、構造体を使うなどハードコピーされるようにしたほうがいい…?

ちなみにMySceneManager といったアプリ全体で利用するものはProjectContextで扱うとよさそうですね。

参考

15
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
12