Mikimemo

個人的な技術・開発メモやポエム

ZenjectDefaultSceneContractConfigで依存するSceneContextを確認用に自動ロード

UnityのZenjectの他の機能の紹介をしようかと思ったところ、 ZenjectDefaultSceneContractConfigという機能を発見。

おそらくv6.1.0くらいから追加されたっぽいんですが、 個人的には全俺が湧く感じの機能、圧倒的僥倖だったのでこちらを紹介します。

Project Contextの使いにくさ

まず、Zenjectを使う上で、ProjectContextというものがあります。 これは、何かしらのScene Contextが読み込まれる前に、 必ず自動的にロードされるContextで、 アプリケーション起動中に常に必要なものをBindしておくには非常に便利なものです。

ただし、このProjectContextには「どんなシチュエーションでも有無を言わずロードされるため、コンテキストの差し替えが効かない」 という積極的に使用できない欠点がありました。 例えば、タイトル画面がら起動する通常フローはサーバーへ通信を行うコンポーネント群を利用するが、 Editor上での特定テストフローの場合は、 ローカルのフィクスチャファイルからデータをロードするモックコンポーネント を利用する場合等が挙げられます。 これらのような、場合によってはInstallerを差し替えたいというケースの場合は ProjectContextではやりにくかったのです。(内部で処理を分岐させれば可能)

ということで、せっかく自動で前提条件をロードしてくれるContextがあるんですが、 切り替えが生じるContextはSceneContextで実装し、 Scene ContextのAuto Runを切った上で、 自前で依存するSceneContextをロードするフローなどを作ったりしてました。

ZenjectDefaultSceneContractConfigによる自動Contextロード

たとえば、以下のようなSampleシーンのContextが DefaultシーンのDefaultというContract NameのContextに依存しているとします。 こういったシチュエーションの場合、 このシーンの起動にはDefaultシーンを予めロードしておく必要があります。

f:id:miki05:20180731021245p:plain

ゲーム起動の通常フローならば、 おそらくDefaultシーンを誰かがロードするようになっていると思いますが(Build Settings / LoadLevel 0でも)、 EditorでSampleシーンを編集後、動作を確認したい場合、Playボタンを押して、このシーンから直接始めたくなります。 つまり、依存するContextは自動でロードしてほしい。

これが、 ZenjectDefaultSceneContractConfigという機能を使うとできます。

使い方はシンプルで、 まずは、Resources以下にZenjectメニューからZenjectDefaultSceneContractConfigアセット作ります。

f:id:miki05:20180731005932p:plain

そして、デフォルトロード対象のContractNameとシーンファイルを設定します。

これで完了です。 Unity上でPlayボタンを押すと、自動的にDefaultシーンがロードされ再生が始まります。 (停止時に自動ロードされたシーンはアンロードされません)

f:id:miki05:20180731013249p:plain

また、このZenjectDefaultSceneContractConfigには、複数のDeafult Contextが登録でき、 依存関係の解決を再帰的にできるようです。 例えば、あるScene ContextにはAというContextを持つシーンが必要で、 A ContextはBというContextを持つシーンが必要な場合 A, B両方ともZenjectDefaultSceneContractConfigに設定しておけば、 双方自動でロードをしてくれます。

テスト用のContextとのスイッチ?

さらに、ZenjectDefaultSceneContractConfigで設定したContextは、 Scene ContextにおいてParent Contract Nameが設定されている状態かつ、 まだシーンにロードされていないときのみ、ロードの処理が走ります。

つまり、予めDefaultシーンのContextと同じContract Nameを設定した別のContext、 例えばテスト用のDefaultシーンを用意しPlay前にロードしておけば、 コードを一切変える必要なく、動作の切り替えができそうです。

f:id:miki05:20180731013817p:plain

ちなみにこのZenjectDefaultSceneContractConfigはEditorのみの機能のようで、 通常のビルドでは明示的に依存シーンをロードするフローが必要です。 そのため、今回のように、あるシーンが他のシーンに依存するが、 確認フローやテスト等で直接起動したい場合のワークフローに有効そうです。

むしろEditorのみの機能だとしたら、 DefaultSceneContractConfigの方をモックやスタブしたContextにしておいたほうが良いのかもしれませんが。