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

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

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

![WS000010.JPG](https://qiita-image-store.s3.amazonaws.com/0/177227/2b5755f1-5bdf-ce7e-c031-075ed18b0873.jpeg)

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

```
using UnityEngine;

public class ShareData : MonoBehaviour {
}
```

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

![WS000011.JPG](https://qiita-image-store.s3.amazonaws.com/0/177227/ab9aca15-d559-ca4b-19d1-1aad76bd2ae0.jpeg)

ShareDataをBindする（コンテナに渡す）ため `ZenjectBinding`というコンポーネントをアタッチします。
Componentsのフィールドに`ShareData`をドラッグ＆ドロップして登録します。
![WS000012.JPG](https://qiita-image-store.s3.amazonaws.com/0/177227/2b0bdd18-558a-895d-7c6d-7171f865aa08.jpeg)
ここに入っているコンポーネントを自動的にBindしてくれるみたいです。

##３.Userクラスを作る
ShareDataを利用する側のクラスを作ります。
`[Inject]` アトリビュートを付けた変数にコンテナがインジェクトしてくれます。

```
using UnityEngine;
using Zenject;

public class User : MonoBehaviour {

    [Inject]
    ShareData shareData;

    void Awake() {
        Debug.Log(shareData.name);
    }
}

```
これを適当なオブジェクトにアタッチして実行してみます。

##４．実行する
`Awake()`の段階で既にインジェクトされているので`NullReferenceException`にならずにログが出力されます。
![WS000013.JPG](https://qiita-image-store.s3.amazonaws.com/0/177227/8308af59-cb5c-7385-961c-4e8d67f435b8.jpeg)

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

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

```
using UnityEngine;

public class UserCreator : MonoBehaviour {

    public GameObject UserPrefab;

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

すると`User`クラスの`Start()`で`NullReferenceException`が発生します。
この書き方だと`ShareData`がインジェクトされていないようです。
![WS000014.JPG](https://qiita-image-store.s3.amazonaws.com/0/177227/2ca725b7-2e25-fbf4-e0de-228181023c5a.jpeg)

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()なら可能）

#マルチシーンでシーンをまたいでインジェクトする
シーンを分けて開発するときに別シーンオブジェクトの参照をぶっ込んでもらいたいときです。
コンテナが別シーンのオブジェクトに参照をぶち込む、というより
それぞれのシーンに配置されたコンテナ同士が同期してそれぞれのシーンのオブジェクトに参照をぶち込む感じです。

##親のコンテナからインジェクトする

今回は作るものは以下の２つのシーンです。

1. マネージャーシーン
1. ゲームシーン

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

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

さきほどの`ShareData`クラスと`User`クラスを別シーンに配置します。
![WS000016.JPG](https://qiita-image-store.s3.amazonaws.com/0/177227/d986dcf2-1861-173a-8e77-32b8b4e45ef1.jpeg)

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

###２．ゲームシーンにSceneContextを追加する
ゲームシーン側に最初の手順で`SceneContext`を追加します。
次に`ParentContractName`にテキトーな名前を入れておきます。
![WS000017.JPG](https://qiita-image-store.s3.amazonaws.com/0/177227/74c14465-6c26-80a0-b899-6a987445139b.jpeg)


###３．マネージャーシーンのSceneContextのContractNamesを設定する
マネージャーシーン側の`SceneContext`の`ContractNames`に先ほど設定したテキトーな名前を入れます。
![WS000018.JPG](https://qiita-image-store.s3.amazonaws.com/0/177227/dcb04644-adb1-b963-4c35-0cca9943d01e.jpeg)


###４．実行する
親を先に実行してもらいたいのでアクティブシーンはManagerSceneにしておきましょう。
これでマネージャーシーンのコンテナの子にゲームシーンのコンテナが登録されました。
実行すると親のコンテナから`User`クラスを引っ張ってきてゲームシーンの`User`クラスにインジェクトしてくれます。
![WS000019.JPG](https://qiita-image-store.s3.amazonaws.com/0/177227/87fb8975-9a15-7094-6b4b-66fa79d7e585.jpeg)

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

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