へっぽこ日記

Unity関係のつぶやきまとめ。マイコンとかもいじります。

UniRxとZenjectで以前作った体力ゲージを改造する

はじめに

今回はUniRxとZenjectで以前作った体力ゲージを改造する記事です。

前回の記事で作ったゲージをZenjectと混ぜて魔改造します。以前の記事からUniRxを使って作っていたいので、今回はZenjectを中心に紹介する記事になると思います。以下のリンクから前回の記事に飛べます。

 

makaroni3018.hatenablog.com

サンプルプロジェクト

github.com

 

 

ちょっとした修正

以前から思っていたことを修正しました。例えばModelはMonoBehaviour継承する意味ないよねとか、Start関数が汚くなるとかですね。

gist6118aab73439fd3ed65d1466946c7663

gistf07c961791e58e758a30238f9098b6c5

gist136722a8cf47a5d8202db310ec180aa6

InitializedとかSetEventとかでStart周りを綺麗にしました。ちなみにBindは購読処理をまとめたメソッドです。ModelはMonoを継承していないので、StartでNew()して生成しています。

そもそもZenjectって?

Unityで使えるDIライブラリです。今回はNew()の場所を変えたいのと、DIを自作するのが面倒くさいので使います。またZenjectとありますが、実は使用するのはアセットストアで公開されていて、現在もアプデもされているExtenjectです。

 

実際に学ぶなら以下の書籍がおすすめです。

booth.pm

Zenjectを実際に使っていく

試しがてらMonoBehaviourを継承していないModelクラスを依存注入してみます。Zenjectではコンストラクタインジェクションや、プロパティインジェクションなど様々な方法がありますが、今回かメソッドインジェクションを使います。また、注入先に [inject] をつける必要があります。

そして、Installerを使ってmodelを生成・注入します。今回は MonoInstaller を作って、 [inject] がついているメソッドインジェクションに注入していきます。

このクラスでModelをNew()して[inject]に注入します

後はSceneContextを生成して、先ほど作ったInstallerと結びつけます。これで準備完了です。

これでPresenterクラスでNewする必要が無くなりました。

 

Viewも注入したい

Modelクラスも注入しましたがViewクラスも注入したいです。そうなるとPresenterはインスペクターから直接アタッチしないので、Monoを継承する必要が無くなります。

そして実際に帰るとこうなりました。

gist3fb23edd27d08e8b695cd66e11b7963f

変わったところは、Viewの [SerializeField] が無くなりました。Zenjectで注入されるので使う必要がなくなりました。そして、メソッドインジェクションだったのがコンストラクタインジェクションになりました。

ちなみにコンストラクタがStartの役割をしていたりする

コンストラクタインジェクションは [inject] をつける必要が無くなります。自動でや注入先を見つけたり、エラーを吐いてくれたりするので基本的にZenjectではコンストラクタインジェクションが推奨されています。

PresenterがMonoを継承しないので、購読処理のリソース破棄がうまくいかなくなります。なので、IDIsposableを実装、CompositeDisposableをNew()してクラスのオブジェが破棄された時点で購読を中止するように結び付けました。

Installerは最初にPresenterを生成した後、Modelを生成して注入しています。ここでキーなのはNonLazyです。こいつがPresenterを明示的に一番最初に生成することで、注入できるようにする。

ViewはGameObjectなのいままでと少し変わります。Installerを作ってやるのではなくすでに準備されている ZenjectBinding を使います。こいつを使うことでViewの公開フィールドをいじらないで注入できます。

最終的にこうなりました

 

すこし気になるところ

コンストラクタをある種Start関数として使っていますが、実は純粋なクラスでもZenject側がStart関数の代わりを用意しています。IInitializabletのInitialized()というStartと同じタイミング・一回だけ実行される関数を使えばわざわざコンストラクタ内で実行する必要ないのですが、問題として実行順序がおかしくなることがあったので、今回使うのはやめました。

 

おわりに

正直またZenjectには慣れていないので間違っているところが多々ありかもしれませんが、一通りはこのパターンで実装していくと機能の追加などが楽になると思います。後、有用なスライドなどがあったら教えてくださると幸いです。

 

是非、読者登録をしていただくと助かります!