はじめに
とりあえずZenjectを動かしてみたくって色々試してみたメモみたいなものです。
いろいろ勘でやってるところがあるのでおかしい場所ありましたらご指摘お願いしますm(__)m
Unityのバージョンは5.6.0f3 Zenjectは5.1.0です。
同一シーン上のオブジェクトにインジェクトする
基本ですね。
例としてShareDataクラスとUserクラスを作ってUserクラスにShareDataの参照をぶっ込みたいと思います。
1.SceneContextを作る
まず、インジェクトしてくれるコンテナを作ります。
GameObject -> Zenject -> SceneContextを選択してSceneContextを作成します。
2.ShareDataクラスを作る
とりあえず参照が取れることを確認できればいいので空っぽのクラスにしました。
using UnityEngine;
public class ShareData : MonoBehaviour {
}
テキトーなオブジェクトを作ってシーンに配置します
ShareDataをBindする(コンテナに渡す)ため ZenjectBindingというコンポーネントをアタッチします。
ComponentsのフィールドにShareDataをドラッグ&ドロップして登録します。

ここに入っているコンポーネントを自動的にBindしてくれるみたいです。
3.Userクラスを作る
ShareDataを利用する側のクラスを作ります。
[Inject] アトリビュートを付けた変数にコンテナがインジェクトしてくれます。
using UnityEngine;
using Zenject;
public class User : MonoBehaviour {
[Inject]
ShareData shareData;
void Awake() {
Debug.Log(shareData.name);
}
}
これを適当なオブジェクトにアタッチして実行してみます。
4.実行する
Awake()の段階で既にインジェクトされているのでNullReferenceExceptionにならずにログが出力されます。

動的に生成したオブジェクトにインジェクトする
シーンに配置されてるオブジェクトにインジェクトすることはできました。
次にゲーム実行中に生成されたオブジェクトにShareDataをインジェクトしてみます。
先ほどのUserクラスをシーンに配置せず、UserCreatorというクラスから生成してみます。
using UnityEngine;
public class UserCreator : MonoBehaviour {
public GameObject UserPrefab;
void Start () {
Instantiate(UserPrefab);
}
}
するとUserクラスのStart()でNullReferenceExceptionが発生します。
この書き方だとShareDataがインジェクトされていないようです。

Instantiateしたゲームオブジェクトにインジェクトする場合はコンテナのInstantiatePrefabを使って生成する必要があるようです。
先ほどのUserCreatorを以下のように変えます。
using UnityEngine;
using Zenject;
public class UserCreator : MonoBehaviour {
public GameObject UserPrefab;
[Inject]
DiContainer container;
void Start () {
container.InstantiatePrefab(UserPrefab);
}
}
コンテナの取得にインジェクトを使っています。
[参考] 開発とかメモ。:【Unity】Zenjectで禅の心を手に入れる
http://yutakaseda3216.hatenablog.com/entry/2017/04/17/124612
別の方法
Instantiateした後にContainer.InjectGameObject()関数にクローンを渡すことでインジェクトすることもできます。
using UnityEngine;
using Zenject;
public class UserCreator : MonoBehaviour {
public GameObject UserPrefab;
[Inject]
DiContainer container;
void Start () {
GameObject instance = Instantiate(UserPrefab);
container.InjectGameObject(instance);
}
}
ただし、上記の書き方だとAwake()にインジェクトが間に合いません。(Start()なら可能)
マルチシーンでシーンをまたいでインジェクトする
シーンを分けて開発するときに別シーンオブジェクトの参照をぶっ込んでもらいたいときです。
コンテナが別シーンのオブジェクトに参照をぶち込む、というより
それぞれのシーンに配置されたコンテナ同士が同期してそれぞれのシーンのオブジェクトに参照をぶち込む感じです。
親のコンテナからインジェクトする
今回は作るものは以下の2つのシーンです。
- マネージャーシーン
- ゲームシーン
マネージャーシーン(親)のオブジェクトをゲームシーン(子)で参照できるようにします。
1.共有したいクラスを別シーンに配置する
さきほどのShareDataクラスとUserクラスを別シーンに配置します。

この状態で実行するとインジェクションがされていないためNullReferenceExceptionになります。
2.ゲームシーンにSceneContextを追加する
ゲームシーン側に最初の手順でSceneContextを追加します。
次にParentContractNameにテキトーな名前を入れておきます。

3.マネージャーシーンのSceneContextのContractNamesを設定する
マネージャーシーン側のSceneContextのContractNamesに先ほど設定したテキトーな名前を入れます。

4.実行する
親を先に実行してもらいたいのでアクティブシーンはManagerSceneにしておきましょう。
これでマネージャーシーンのコンテナの子にゲームシーンのコンテナが登録されました。
実行すると親のコンテナからUserクラスを引っ張ってきてゲームシーンのUserクラスにインジェクトしてくれます。

子になるコンテナはいくつあってもいいみたいなので、複数シーン読み込んでも使えます。
しかし子同士のコンテナはアクセスできません。
ちなみに複数のコンテナを全部1つのコンテナとして扱うにはSceneDecoratorContextを使えばいいっぽいです。(Bindがごちゃごちゃになりそうですが)
SceneDecoratorContextについてはちょっと使い方がハッキリわからないのでまた機会があれば書こうと思います。

