Skip to content

「Unity Zenject完全に理解した」に参加してきたよという話

Posted in 技術記事/勉強会

2018年9月6日に「Unity Zenject完全に理解した」というイベントがあったので参加してきました。
全体的に高度なので、Zenjectとはなんぞや?というような方は、4、7、おまけ辺りを先に見るのをオススメします。

ライブ配信

ゲーム案件にZenject導入した経験を語る @KaseliaePenguin

導入した経緯

データが増えてく、初期化フローや依存関係が汚くなる、initialize祭り
→zenjectで解決

シーン設計

本番とデバッグの差し替えを容易にしたい
SceneContextの親子付けを活用
→シーンの読み込み時、親となるSceneContextを自動で取得するようにする
→シーンを機能で切り分けておけばデバッグ時の差し替えが楽にできる

クラス設計

MVRP+CleanArcitecture(一部)
modelはinterfaceで区切ってAsSingleでBind

Bindの方式

AsSingle…シングルトン、破棄できない
AsCached…キャッシュされる、破棄されるまで使い回される
AsTransient…毎回新規作成、デフォルト
詳細はブログにて
(AsSingleだったので)取り回しがつらくなった
Containerから生成されるクラスのメソッドはnew()→[Inject]で行われる
→すごい罠、注意

インゲームへの適用

ゲーム内キャラには不敵だった
→イテレーションが遅い、Injectする情報が多い

適用基準

する→よく参照されるもの、デバッグで差し替えたいもの
しない→細かいもの、Zenjectへの理解が浅い人が触るもの
使い所を見極めるのは大変、ハイリスクハイリターン
zenjectを使わなくなっても困らないようにする(≒zenjectに依存しない)

文脈を操る美しきZenjectプロジェクトからの眺め 〜Contextの扱い方と活用方法〜 @mikito0521

contextとは

これを理解できたらzenject理解できる
依存関係を解決してくれるいいやつ
使いこなそうとするとわけわからん

context=文脈

iOSで/Androidで/UnitEditorで
本番サーバで/開発サーバで/モックデータで
キャラ強化シーンを/バトルシーンを
通常プレイ/テストプレイ
→contextは条件や状態を明示的に分割したもの

分割しているので
本番環境とテスト環境を差し替えたりできる=contextのスイッチ

Contextの種類

Project Context…Project全体で利用するものに使う
Scene Context…基本、シーンに1つ
Scene Decorator Context…Scene Contextの機能を追加変更する
Game Object Context…GameObject1つにつき1つ

Context親子関係

親を持てる
親から子へはアクセスできない
Project Context
└Scene Context─Scene Decorator Context
└Game Object Context

Contextと動的生成

動的生成かつDI Containerを利用するものはFactory
Scene Context…シーンのロード、アンロードで制御
Game Object Context…プレファブ化しておいてFactory
FromSubContainerResolve…指定したコンテナの窓口となる

Contextの構築

Contextに対し、Installerを差し替えることで状態を変化
Interface設計がしっかりしてると扱いやすい

実装例(スライドより転載)

インタフェース完全に理解した @toRisouP

クラスの継承

属性を引き継ぐ
元のルールは変えられない

インタフェース

クラスと比較して自由
利用者がいる(定義する)

インタフェースの利点

疎結合にできる=依存関係を整理できる
利用側、実装側を同時に作れる

依存の解決

  • ServiceLocator
    • シングルトンに問い合わせる
    • 簡単だが依存がきつい
  • DI Container
    • zenject
    • ハイリスクハイリターン

小ネタ

プロパティ…getオンリーがよい
getcomponent…実はインターフェイスを指定できる
拡張メソッドを追加できる
structにインターフェースを被せられる
R#やRiderだと勝手に書いてくれる

  • 明示的な実装が可能
    • 暗黙的な実装→アクセスレベルはpublic
    • 明示的な実装→インタフェース経由じゃないと呼べない

Zenject完全には理解できなかった〜実運用におけるアンチパターンとその回避策〜 @notargs

公開資料:Zenject完全には理解できなかった

ZenAutoInjector

同じGameObjectのComponentに自動でInject(的なこと)をしてくれる

MethodInjection

[inject]に依存しすぎないようにする機能

MonoBehaviourのInject

動的に生成されるObjectをSceneContextでInjectしてはならない

Zenjectの機能をご紹介 〜テストの巻〜@nozomin770

資料は後日公開予定
ZenjectUnitTestFixture/ZenjectIntegrationTestFixture
テストができる機能
SceneTestFixture
DIを上書きできるテスト
自動テストができると強力

Zenjectはじめの一歩:ゲームデータをScriptableObjectでInject! @lucifuges

公開資料:Zenjectはじめの一歩

設計が間違ってるとzenjectは使いこなせない
ただ使い所が無いわけではない

使い所

Scriptable objectでアイテムやキャラのステータスを持つ
→GameObjectに手動で参照つける必要がある→めんどい

必要なもの

Scriptable Object Installer…Scriptable Objectの代わりに継承する
Project Context…Resourcesフォルダ内に作り、↑のScriptable Objectを登録する
Scene Context…zenjectを動かすやつ。シーンに1つ置いておく
呼ぶ側…[SerializeField]を[Zenject.Inject]に変更

注意

Injectはそこそこ重い
→大量に複製されるObjectは避ける(弾とか)
ScriptableObjectをロードした時に全部先読みするので、重いリソースは避ける
→画像モリモリとかにしない(アセットバンドルに逃がしたりする)

おまけ

まとめ

Zenjectは銀の弾丸ではありません。おおよそどの登壇者も「ハイリスクハイリターン」というようなことを言っていました。
個人、小規模、売り切りタイプではほとんど恩恵は無く、逆に大規模、大人数、運営系のゲームで、企画立ち上げ時に検討した場合に真価を発揮しそうです。プロジェクトの設計をいかにしっかり出来るか、Zenject導入の効果的な範囲を見極められるか、そのあたりがキモではないかと。
最近のゲームは長期運営が前提になることが多く、自然と求められる設計は「変更やテストに強い」ものとなります。それを満たすための設計をしていく上で発生する問題を解決するのがzenjectということです。(この辺りはおまけの「Zenject入門」に詳しく書いてあります)
なんとなくですが、どういう状況で必要になるか、どういう前提能力が必要になるかは分かってきたかなと思います。
まずはC#のInterface、UnityのScriptableObject辺りから習得していくことにします…

Be First to Comment

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です