はじめに
とりあえず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
についてはちょっと使い方がハッキリわからないのでまた機会があれば書こうと思います。