【Unity】Zenjectをマルチシーンで使うときの3つの方法

Zenject関係の過去記事

 

yutakaseda3216.hatenablog.com

 

 

yutakaseda3216.hatenablog.com

 

 

マルチシーンでZenjectを使う

 

少し慣れてきた人向けです

 

Zenjectの中核となるDiContainerは、SceneContextというクラスに紐付いている

 

SceneContextが破棄されることでBindされていたデータも破棄されてしまうため、シーンを跨いでSceneContextが破棄される場合、データを保持できない

 

また、複数シーンを使用する場合、各々にSceneContextが存在する場合、何もしなければContext間でBindされたインスタンスは共有されない

 

そのため、マルチシーン用の機能を使う必要がある

 

方法は三種類ある

 

 

1.ProjectContextを使用する

https://github.com/modesttree/Zenject#global-bindings

 

ProjectContextをSceneContextと同様に作成してprefab化する

InstallerをprefabにアタッチしてAssets/Resources/以下に置くことで

いずれかのSceneContextが読み込まれた際に自動でResources.Loadで生成される

ようになる

 

ProjectContextの特徴として

 

  • DontDestroy属性付きで生成される
  • 全てのSceneContextから参照される

 

ため、各SceneContextから、ProjectContextでBindされたインスタンスを参照することが可能になる

 

また、ProjectContextを操作したい場合はsingletonになっているので

 

ProjectContext.Instance.Container

 

で取得できる

 

どのSceneContextが読み込まれた時でも生成されるので、デバッグでも本番環境でもいてほしいBindインスタンスはこれで良いと思う

 

 

ただ、デメリットとして、いついかなる時でもSceneContextが生成されるとひっついてくるので、Testなどには向かない可能性高し

 

2.ContractNameを使用したParenting

https://github.com/modesttree/Zenject#scene-parenting

 

ProjectContextを使用しない方法その1

 

SceneContextには、ContractNameというパラメータを設定できる

 

これの

 

f:id:yutakaseda3216:20170622174720p:plain

 

ここ

 

f:id:yutakaseda3216:20170622174734p:plain

 

ContractNameを設定することで、SceneContextに属性を設定することができる

 

また勘のいい人はすでにお気づきかもしれないが

 

すぐ下に"ParentContractName"なるパラメータがある

 

ここに指定したContractNameの属性を持つSceneContextがParentとして参照されることで親のインスタンスがBindされているかの様に振る舞うことができるができる

 

Parentに指定したSceneContextが読み込まれていない場合、エラーになるので読み込み順には気をつけよう

 

また、Parentに指定されたSceneContextが先に破棄された場合も同様にエラーになる

 

特徴をまとめる

  • Parentは子のContextを参照できない
  • Parentは子のContextより先に読み込まれていないといけない
  • Parentが子より先に破棄されてはいけない

 

使用するメリットとして、同じContractNameをつけることで

デバッグ

本番用

テスト用

などのContextを用意し、状況に応じてシーンを付け替え、動作を変えることができる点があげられる

 

子からParentになっているSceneContextのContainerを指定してアクセスする場合

子のContainerをInjectで取得して

 

Container.ParentContainer

で取得できる

 

3.ContractNameを使用したDecorating

https://github.com/modesttree/Zenject#scene-decorators

 

ProjectContextを使用しない方法その2

 

前述のSceneParentingよりもシンプル

 

SceneContextを作成するのと同じ様に、DecoratorContextを作成する

 

f:id:yutakaseda3216:20170622175838p:plain

 

DecoratedContractNameに、SceneContextに設定したContractNameを指定する

あとはInstallerを追加して〜で終わり

 

デバッグコマンドの追加や、元となるシーンに対して何かを付加する場合に使用すると良い

元のシーンを全くいじることなく、何かの機能を付与することができる

 

 

またSceneParentingを使用した場合と違って

 

  • DecoratorContextと指定したSceneContextは相互に参照できる
  • DecoratorContextのあるシーンは指定したSceneContextの前にロードされていないといけない

 

点に注意する、特に二個目はクセが強いと思うので・・・

 

 

まとめ

 

SceneParentingだけ使えばいいんじゃないかな感があるものの、それぞれメリットがあるので一考する

 

あと、UniRxとMVP(っぽい)設計とZenjectを組み合わせたアーキテクチャを試行錯誤しながら大体まとめられた気がするので、いつか書きたいなと思う(弱気)

 

Zenjectを使ってUnityの最前線(笑)にいる気持ちで開発しよう!

 

 

ついでに

実はもう一個シーン間の受け渡し方法があるんですが、ZenjectSceneHandlerで調べてください

めんどくさすぎるので紹介しませんでした