【Unity】Zenjectをマルチシーンで使うときの3つの方法
Zenject関係の過去記事
マルチシーンで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になっているので
で取得できる
どのSceneContextが読み込まれた時でも生成されるので、デバッグでも本番環境でもいてほしいBindインスタンスはこれで良いと思う
ただ、デメリットとして、いついかなる時でもSceneContextが生成されるとひっついてくるので、Testなどには向かない可能性高し
2.ContractNameを使用したParenting
https://github.com/modesttree/Zenject#scene-parenting
ProjectContextを使用しない方法その1
SceneContextには、ContractNameというパラメータを設定できる
これの
ここ
ContractNameを設定することで、SceneContextに属性を設定することができる
また勘のいい人はすでにお気づきかもしれないが
すぐ下に"ParentContractName"なるパラメータがある
ここに指定したContractNameの属性を持つSceneContextがParentとして参照されることで親のインスタンスがBindされているかの様に振る舞うことができるができる
Parentに指定したSceneContextが読み込まれていない場合、エラーになるので読み込み順には気をつけよう
また、Parentに指定されたSceneContextが先に破棄された場合も同様にエラーになる
特徴をまとめる
- Parentは子のContextを参照できない
- Parentは子のContextより先に読み込まれていないといけない
- Parentが子より先に破棄されてはいけない
使用するメリットとして、同じContractNameをつけることで
デバッグ用
本番用
テスト用
などのContextを用意し、状況に応じてシーンを付け替え、動作を変えることができる点があげられる
子からParentになっているSceneContextのContainerを指定してアクセスする場合
子のContainerをInjectで取得して
で取得できる
3.ContractNameを使用したDecorating
https://github.com/modesttree/Zenject#scene-decorators
ProjectContextを使用しない方法その2
前述のSceneParentingよりもシンプル
SceneContextを作成するのと同じ様に、DecoratorContextを作成する
DecoratedContractNameに、SceneContextに設定したContractNameを指定する
あとはInstallerを追加して〜で終わり
デバッグコマンドの追加や、元となるシーンに対して何かを付加する場合に使用すると良い
元のシーンを全くいじることなく、何かの機能を付与することができる
またSceneParentingを使用した場合と違って
- DecoratorContextと指定したSceneContextは相互に参照できる
- DecoratorContextのあるシーンは指定したSceneContextの前にロードされていないといけない
点に注意する、特に二個目はクセが強いと思うので・・・
まとめ
SceneParentingだけ使えばいいんじゃないかな感があるものの、それぞれメリットがあるので一考する
あと、UniRxとMVP(っぽい)設計とZenjectを組み合わせたアーキテクチャを試行錯誤しながら大体まとめられた気がするので、いつか書きたいなと思う(弱気)
Zenjectを使ってUnityの最前線(笑)にいる気持ちで開発しよう!
ついでに
実はもう一個シーン間の受け渡し方法があるんですが、ZenjectSceneHandlerで調べてください
めんどくさすぎるので紹介しませんでした