ZenjectSceneLoader でシーン遷移を行う【Extenject(Zenject)】

直接関与しているわけではないですが,
前回の記事でシーン遷移を行う処理にZenjectSceneLoaderを使ってみました.
xrdnk.hateblo.jp

ZenjectSceneLoader

UnityEngine.SceneManagement.SceneManager の Zenject 版.

サンプルスクリプト

using UnityEngine.SceneManagement;
using UnityEngine;
using UnityEngine.UI;

using Zenject;
using UniRx;

using xrdnk.Const;

namespace xrdnk.SceneLoader
{
    public class LoadMainScene : MonoBehaviour
    {
        [SerializeField] private Button Button_Start;

        private ZenjectSceneLoader _ZenjectSceneLoader;

        [Inject]
        private void Construct(ZenjectSceneLoader sceneLoader)
        {
            _ZenjectSceneLoader = sceneLoader;

            Button_Start
                .OnClickAsObservable()
                .Subscribe(_ => _ZenjectSceneLoader.LoadScene(SceneName.MAIN_SCENE, LoadSceneMode.Single));
        }
    }
}

特別バインド設定する必要なし.SceneContextがあれば,ZenjectSceneLoaderをInjectしてくれるという認識.
これでシーン遷移の処理が出来ていました.

ZenjectSceneLoader.LoadScene / LoadSceneAsync

ZenjectSceneLoader のスクリプトを中身を見てみると,サンプルスクリプトのような使い方では,
普通に SceneManager.LoadScene / LoadSceneAsync を利用していることに変わりありません.

        public void LoadScene(
            string sceneName,
            LoadSceneMode loadMode = LoadSceneMode.Single,
            Action<DiContainer> extraBindings = null,
            LoadSceneRelationship containerMode = LoadSceneRelationship.None,
            Action<DiContainer> extraBindingsLate = null)
        {
            PrepareForLoadScene(loadMode, extraBindings, extraBindingsLate, containerMode);

            Assert.That(Application.CanStreamedLevelBeLoaded(sceneName),
                "Unable to load scene '{0}'", sceneName);

            SceneManager.LoadScene(sceneName, loadMode);

            // It would be nice here to actually verify that the new scene has a SceneContext
            // if we have extra binding hooks, or LoadSceneRelationship != None, but
            // we can't do that in this case since the scene isn't loaded until the next frame
        }

            public AsyncOperation LoadSceneAsync(
            string sceneName,
            LoadSceneMode loadMode = LoadSceneMode.Single,
            Action<DiContainer> extraBindings = null,
            LoadSceneRelationship containerMode = LoadSceneRelationship.None,
            Action<DiContainer> extraBindingsLate = null)
        {
            PrepareForLoadScene(loadMode, extraBindings, extraBindingsLate, containerMode);

            Assert.That(Application.CanStreamedLevelBeLoaded(sceneName),
                "Unable to load scene '{0}'", sceneName);

            return SceneManager.LoadSceneAsync(sceneName, loadMode);
        }

PrepareForLoadScene で シーン遷移時に,第三引数で追加バインド設定を,
第四引数で SceneContext との関係性を,第五引数で Late で追加バインド設定を行うことができます.

PrepareForLoadScene の中身はこんな感じ.

        void PrepareForLoadScene(
            LoadSceneMode loadMode,
            Action<DiContainer> extraBindings,
            Action<DiContainer> extraBindingsLate,
            LoadSceneRelationship containerMode)
        {
            if (loadMode == LoadSceneMode.Single)
            {
                Assert.IsEqual(containerMode, LoadSceneRelationship.None);

                // Here we explicitly unload all existing scenes rather than relying on Unity to
                // do this for us.  The reason we do this is to ensure a deterministic destruction
                // order for everything in the scene and in the container.
                // See comment at ProjectKernel.OnApplicationQuit for more details
                _projectKernel.ForceUnloadAllScenes();
            }

            if (containerMode == LoadSceneRelationship.None)
            {
                SceneContext.ParentContainers = null;
            }
            else if (containerMode == LoadSceneRelationship.Child)
            {
                if (_sceneContainer == null)
                {
                    SceneContext.ParentContainers = null;
                }
                else
                {
                    SceneContext.ParentContainers = new[] { _sceneContainer };
                }
            }
            else
            {
                Assert.IsNotNull(_sceneContainer,
                    "Cannot use LoadSceneRelationship.Sibling when loading scenes from ProjectContext");
                Assert.IsEqual(containerMode, LoadSceneRelationship.Sibling);
                SceneContext.ParentContainers = _sceneContainer.ParentContainers;
            }

            SceneContext.ExtraBindingsInstallMethod = extraBindings;
            SceneContext.ExtraBindingsLateInstallMethod = extraBindingsLate;
        }

SceneContext との関係性

Container には階層関係があります.
詳細はこちらのいもさんの資料を見るといいかもしれない…

speakerdeck.com

終わりに

正直現段階では第三引数から第五引数の機能を利用していないので何とも言えない.
まだまだExtenjectは理解しないといけないところが一杯ありますね.
フル機能を利用する時がいたらまた新たに記事を出す所存.

参考資料

monry.hatenablog.com