Slide 1

Slide 1 text

Zenject Example ~Container の分割編~ @ いも 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 2

Slide 2 text

いも twitter: @adarapata ゲーム作ったりしてます 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 3

Slide 3 text

宣伝 「Zenject チョットワカルBook 」を書きました ↓Booth 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 4

Slide 4 text

今日話すこと Installer 肥大化問題 Zenject のSubContainer について Zenject チョット触り始めてる人向け 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 5

Slide 5 text

Installer 肥大化問題 public class SomeInstaller : MonoInstaller { public override void InstallBindings() { // Player 関連のBind Container.Bind().AsCached(); Container.Bind().AsCached(); // Player しか依存してない Container.Bind().AsCached(); // Player しか依存してない ~~~ Container.Bind().AsCached(); // Player しか依存してない // Enemy 関連のBind Container.Bind().AsCached(); Container.Bind().AsCached(); // Enemy しか依存してない } } 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 6

Slide 6 text

Installer 肥大化問題 1 シーンに必要なものがそれなりに大きくなると起きる問題 あらゆる依存関係が1 シーンに刻まれる Scene のInsaller が細かい依存関係を知ることになる 不要な衝突も発生する可能性が出てくる 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 7

Slide 7 text

不要な衝突が発生する public class SomeInstaller : MonoInstaller { public override void InstallBindings() { // Player 関連のBind Container.Bind().AsCached(); Container.Bind().AsCached(); // Player しか依存してない Container.Bind().AsCached(); // Player のLife を表現したい // Enemy 関連のBind Container.Bind().AsCached(); Container.Bind().AsCached(); // Enemy しか依存してない Container.Bind().AsCached(); // Enemy のLife を表現したい } } 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 8

Slide 8 text

不要な衝突が発生する 回避できないことはないがちょっと厳しい Container を分けてスマートにしたい 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 9

Slide 9 text

やること SubContainer の利用 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 10

Slide 10 text

Container の階層関係 Container は階層関係を持つことができる まず自身のContainer を探して、解決できないなら親のContainer を 探す 親のContainer で見つからなかったらその親を~を繰り返す ProjectContext がどこでもInject できるのは、このContainer の最上 位にいるから 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 11

Slide 11 text

Container の階層関係(Parent Contract の場合) Context を境界にContainer が繋がっている 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 12

Slide 12 text

1Context の内部だけでContainer の階層関係を作ることもできる 子にあたるContainer のことをSubContainer と呼ぶ 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 13

Slide 13 text

SubContainer にPlayer が必要とする要素をまとめてしまえば、 Container 内部で衝突しない 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 14

Slide 14 text

FromSubContainerResolve public class SomeInstaller : MonoInstaller { public override void InstallBindings() { // SubContainer から解決する Container.Bind().FromSubContainerResolve() .ByMethod(InstallSubContainer); // Enemy 関連のBind } // SubContainer にInstall させる public void InstallSubContainer(DiContainer subContainer) { subContainer.Bind().AsCached(); subContainer.Bind().AsCached(); subContainer.Bind().AsCached(); } } 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 15

Slide 15 text

FromSubContainerResolve Bind するオブジェクトをSubContainer から探して解決する 今回だとSubContainer からPlayer を探して解決する このメソッドの後には「何でSubContainer を作るか」のBy~~ メソッ ドを定義する ByMethod メソッドを呼んでInstall する ByInstaller Installer なクラスを呼んでInstall する ほかにもいっぱいある 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 16

Slide 16 text

Installer で解決する場合 public class SomeInstaller : MonoInstaller { public override void InstallBindings() { // SubContainer にInstaller でInstall して解決する Container.Bind().FromSubContainerResolve() .ByInstaller().AsCached(); // Enemy 関連のBind } } public class PlayerInstaller : Installer { public override void InstallBindings() { Container.Bind().AsCached(); Container.Bind().AsCached(); Container.Bind().AsCached(); } } 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 17

Slide 17 text

Player をSubContainer から引っ張って解決する Life PlayerDependentA はContainer からは見えない Container 単位で役割をグルーピングしやすい 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 18

Slide 18 text

GameObjectContext public class PlayerBehaviour : MonoBehaviour { [Inject] PlayerDependentA depA; [Inject] Life life; } ↑ こういうのをSubContainer でBind したいとする SubContainer にMonoBehavior なオブジェクトをBind する場合、 GameObjectContext をアタッチする必要がある 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 19

Slide 19 text

GameObjectContext SceneContext ProjectContext と同じContext の一種 Context はInstall を行うエントリポイント それぞれInjection のスコープが違う ProjectContext: ゲーム全体 SceneContext: シーン内 GameObjectContext: アタッチされたGameObject 以下 SceneContext のContainer にBind するとシーン全体にInject されるの で、GameObjectContext をSubContainer として狭い範囲へのInject を 行える 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 20

Slide 20 text

MonoBehavior でない場合 public class SomeInstaller : MonoInstaller { public override void InstallBindings() { // SubContainer にInstaller でInstall して解決する Container.Bind().FromSubContainerResolve() .ByInstaller().AsCached(); } } public class PlayerInstaller : Installer { public override void InstallBindings() { Container.Bind().AsCached(); Container.Bind().AsCached(); Container.Bind().AsCached(); } } SubContainer の作り方が、直接Installer を指定する形になる 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 21

Slide 21 text

MonoBehaviour の場合 いつものSceneContext のノリで対象のPrefab にアタッチする 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 22

Slide 22 text

MonoBehaviour の場合 public class SomeInstaller : MonoInstaller { [SerializeField] private GameObject _playerPrefab; public override void InstallBindings() { // GameObjectContext のついたPrefab を生成してInstall する Container.Bind().FromSubContainerResolve() .ByNewContextPrefab(_playerPrefab).AsCached(); } } public class SubInstaller : MonoInstaller { public override void InstallBindings() { // Zenject Binding をアタッチするのもアリ Container.Bind().FromComponentOnRoot(); Container.Bind().AsCached(); Container.Bind().AsCached(); } } 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 23

Slide 23 text

Context を跨いで同じことが行われる 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 24

Slide 24 text

まとめ 1 つのContainer にどんどんBind していくと衝突や可読性の問題が現 れる SubContaienr に分離してスコープを狭めよう MonoBehaviour の場合はGameObjectContext を使おう MonoBehaviour でもPureClass でもSubContainer の考え方は変わら ない。 Context があるかどうかだけ 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes

Slide 25

Slide 25 text

おわり 2019/09/23 Unite Tokyo 2019 Eve2 LT Fes