Unity・3DCG技術ブログ

TAもどきによるUnity・3DCGに関する記事をアップします。

UniRx+Zenjectで作るシーン遷移基盤 メモその2ZenjectBindingとか

例えばタイトル画面からホーム画面に遷移するとして、基盤を使う側のコードはこんな感じとなります。

コード

using UnityEngine;
using UnityEngine.UI;
using UniRx;
using Zenject;

public class Title : SceneBase
{
    [Inject(Id = "start")] Button startButton;
    [Inject] TransitionController transitionController;

    void Start()
    {
        // タッチでホーム画面へ
        startButton.OnClickAsObservable().Subscribe(_ =>
        {
            transitionController.LoadScene("Home", TransitionController.LoadingMode.LongLoading);
        }).AddTo(this);
    }
}
using UnityEngine;
using UnityEngine.UI;
using Zenject;
using UniRx;

public class Home : SceneBase
{
    [Inject(Id = "quest")] Button questButton;
    [Inject] TransitionController transitionController;

    void Start()
    {
        // Something code here ...
    }
}

[SerializeField]でオブジェクトを直接リンクして参照するかわりに ZenjectのInjectアトリビュートでもってインスタンスを注入します。

ZenjectBinding

UIの参照がInjectされるためにZenjectBindingコンポーネントを使用します。

ZenjectBindingというコンポーネントidentifierとともに貼り付けておきます。 f:id:serialtv:20190817231014p:plain

ProjectContext

Resources以下にあるProjectContext.prefabはZenjectの仕組みによってゲーム起動直後にシーンに読み込まれます。 そして、DontDestroyなのでシーン遷移しても消えないグローバルオブジェクトです。 この性質を利用して、ProjectContext直下にトランジション演出用のコンポーネントTransitionControllerを置きました。

f:id:serialtv:20190817232046p:plain

こんな具合でProjectContext以下に置いたCanvasにあります。 そしてTransitionControllerのインスタンスProjectContextのグローバルなInstallerに下記のような コードでアタッチさせています。

コード

using UnityEngine;
using Zenject;
using UniRx;
using System.Linq;

/// <summary>
/// ProjectContextにアタッチされるグローバルなInstaller.
/// </summary>
public class ApplicationInstaller : MonoInstaller
{
    [SerializeField] TransitionController transitionController;

    public override void InstallBindings()
    {
        Container.Bind<TransitionController>().FromInstance(transitionController).AsSingle();
    }
}

あと色々省略してますがTransitionControllerのコードです。

public class TransitionController : MonoBehaviour
{
    public enum LoadingMode
    {
        // ローディング画面を挟まない
        None,
        // 長めのローディングになりそうな場合
        LongLoading,
    }

    [SerializeField] GameObject view = default;
    [SerializeField] GameObject block = default;
    [SerializeField] Material transitionMaterial = default;
    LoadingMode loadingMode = LoadingMode.None;

    public void LoadScene(string sceneName, LoadingMode mode = LoadingMode.None, object argument = null)
    {
        loadingMode = mode;
        NavigationService.NavigateSingleAsync(sceneName, argument)
        .Subscribe(_ => { }, e => Debug.LogException(e));
    }

    public void LoadSceneAdditive(string sceneName, object argument = null, LoadingMode mode = LoadingMode.None)
    {
        loadingMode = mode;
        NavigationService.NavigateAsync(sceneName, argument)
        .Subscribe(_ => { }, e => Debug.LogException(e));
    }

    void Awake()
    {
        GameObject.DontDestroyOnLoad(this.gameObject);

        NavigationService.AsyncBroker.Subscribe<AsyncBeginLoadSceneEvent>(_ => Observable.FromCoroutine(Show)).AddTo(this);
        NavigationService.AsyncBroker.Subscribe<AsyncAfterLoadSceneEvent>(_ => Observable.FromCoroutine(Hide)).AddTo(this);
        NavigationService.Broker.Receive<BackButtonEvent>().Subscribe(_ => OnBackEvent()).AddTo(this);
        NavigationService.Broker.Receive<TapBlockEvent>().Subscribe(_ => block.SetActive(true)).AddTo(this);
        NavigationService.Broker.Receive<TapUnblockEvent>().Subscribe(_ => block.SetActive(false)).AddTo(this);
    }

 ....~~いろいろ略~~
}

最後に

その3に続く...(予定)