37
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Zenjectでコンポーネントの参照をインジェクトする

Last updated at Posted at 2017-04-20

#はじめに
とりあえずZenjectを動かしてみたくって色々試してみたメモみたいなものです。
いろいろ勘でやってるところがあるのでおかしい場所ありましたらご指摘お願いしますm(__)m
Unityのバージョンは5.6.0f3 Zenjectは5.1.0です。

#同一シーン上のオブジェクトにインジェクトする
基本ですね。
例としてShareDataクラスとUserクラスを作ってUserクラスにShareDataの参照をぶっ込みたいと思います。
##1.SceneContextを作る
まず、インジェクトしてくれるコンテナを作ります。
GameObject -> Zenject -> SceneContextを選択してSceneContextを作成します。

WS000010.JPG

##2.ShareDataクラスを作る
とりあえず参照が取れることを確認できればいいので空っぽのクラスにしました。

using UnityEngine;

public class ShareData : MonoBehaviour {
}

テキトーなオブジェクトを作ってシーンに配置します

WS000011.JPG

ShareDataをBindする(コンテナに渡す)ため ZenjectBindingというコンポーネントをアタッチします。
ComponentsのフィールドにShareDataをドラッグ&ドロップして登録します。
WS000012.JPG
ここに入っているコンポーネントを自動的に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にならずにログが出力されます。
WS000013.JPG

#動的に生成したオブジェクトにインジェクトする
シーンに配置されてるオブジェクトにインジェクトすることはできました。
次にゲーム実行中に生成されたオブジェクトにShareDataをインジェクトしてみます。

先ほどのUserクラスをシーンに配置せず、UserCreatorというクラスから生成してみます。

using UnityEngine;

public class UserCreator : MonoBehaviour {

    public GameObject UserPrefab;

	void Start () {
        Instantiate(UserPrefab);
	}	
}

するとUserクラスのStart()NullReferenceExceptionが発生します。
この書き方だとShareDataがインジェクトされていないようです。
WS000014.JPG

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. マネージャーシーン
  2. ゲームシーン

マネージャーシーン(親)のオブジェクトをゲームシーン(子)で参照できるようにします。

###1.共有したいクラスを別シーンに配置する

さきほどのShareDataクラスとUserクラスを別シーンに配置します。
WS000016.JPG

この状態で実行するとインジェクションがされていないためNullReferenceExceptionになります。

###2.ゲームシーンにSceneContextを追加する
ゲームシーン側に最初の手順でSceneContextを追加します。
次にParentContractNameにテキトーな名前を入れておきます。
WS000017.JPG

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

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

子になるコンテナはいくつあってもいいみたいなので、複数シーン読み込んでも使えます。
しかし子同士のコンテナはアクセスできません。

ちなみに複数のコンテナを全部1つのコンテナとして扱うにはSceneDecoratorContextを使えばいいっぽいです。(Bindがごちゃごちゃになりそうですが)
SceneDecoratorContextについてはちょっと使い方がハッキリわからないのでまた機会があれば書こうと思います。

37
31
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
37
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?