ZenjectでUnityのPrefabの外部参照を減らす
Extenject / Zenject のID指定を使ってPrefab外の参照を減らしました。
レベル数や所持コイン数のテキストを表示する場合にInspectorで書き込むテキストコンポーネントを指定することがよくあります。
この例では、GameMain1
が 2つのテキストコンポーネントの参照を持っていますが、参照先が外部の Header
Prefab内オブジェクトであるため、Prefabの変更を Apply All
しても参照先の情報がSceneファイルに残ってしまいます。
このような状況では、複数人でSceneを編集した場合に衝突が起きやすくなるのでヤメたい。
その場合の選択肢として、参照先をSingletonにするという方法もありますが、既存コンポーネントの場合はそうも行きません。
そこで、Zenjectを使って参照コンポーネントの情報を取得します。
概要
こんな感じで、ボタンを押したらレベルアップしたり、ランダムなコイン獲得したりするサンプルを作ります。
直接参照せずに、Zenjectでバインドするので、GameMain2
とHeader
のPrefabは独立している。
Zenjectの導入
OpenUPM使ってる人は、コマンドラインで下記コマンドで処理
openupm add com.svermeulen.extenject
そうでない人は Unity Asset StoreからExtenject Dependency Injection IOC を導入
Zenjectの IDバインド用 MonoInstallerクラス
using System;
using UnityEngine;
using Zenject;
public class ZenjectIdBinding : MonoInstaller<ZenjectIdBinding>
{
[Serializable]
class BindInfo
{
public string key;
public Component component;
}
[SerializeField] BindInfo[] m_bindInfos;
public override void InstallBindings()
{
foreach (var info in m_bindInfos)
{
Container.Bind(info.component.GetType()).WithId(info.key).FromInstance(info.component).AsCached();
}
}
}
やってることは、key
として名前を指定してコンポーネントを登録し、keyをIDとしてコンポーネントをInject対象として登録しているだけ
MonoInstallerをシーンへ登録
Hierarchy Viewで右クリックし、ポップアップメニューから Zenject > SceneContext を選ぶ
- 追加されたSceneContextオブジェクトに、
ZenjectIdBinding
コンポーネントを追加 - SceneContextコンポーネントのMonoInstallerに
ZenjectIdBinding
コンポーネントを登録 ZenjectIdBinding
コンポーネントに Injectしたいコンポーネントを登録
これで、LevelNumとCoinNum のテキストが登録された。
ZenjectでInjectするコード
using UnityEngine;
using TMPro;
using Zenject;
public class GameMain2 : MonoBehaviour
{
// ZenjectのIDで値をバインドする
[Inject(Id = "LevelNum")]
TextMeshProUGUI m_levelText;
[Inject(Id = "CoinNum")]
TextMeshProUGUI m_coinText;
int m_level = 1; // レベルは1から
int m_coin = 0;
// Start is called before the first frame update
void Start()
{
m_levelText.text = $"{m_level}";
m_coinText.text = $"{m_coin}";
}
public void LevelUp()
{
++m_level; // レベルは必ず1ずつ上がる
m_levelText.text = $"{m_level}";
}
public void GetCoin()
{
// ランダムな数のコイン獲得
m_coin += UnityEngine.Random.Range(100, 1000);
m_coinText.text = $"{m_coin:#,0}"; // コインはカンマ区切りあり
}
}
重要なのは、[Inject(Id = "LevelNum")]
の部分だけ。
LevelUp()
とGetCoin()
は、ボタンを押したときに呼び出されるように登録。
まとめ
ということで完成
ZenjectのID指定を使うことで、最小のコード変更で使いたいコンポーネントを取得することができました。
- Zenjectを導入
- Scene Contextをシーンに追加
- Scene ContextのMonoInstallerに
ZenjectIdBinding
コンポーネントを登録 ZenjectIdBinding
コンポーネントに、使いたいコンポーネントにIDを付けて登録- コンポーネントを利用するコードで、メンバ変数のアトリビュートに
[Inject (Id = "ID文字列")]
を記述
これで、自作クラスであれば Prefab外のコンポーネントへの参照をなくすことができるようになりました。
ただし、既存クラスの参照や動的に生成するコンポーネントへの参照はひと工夫必要です。
-
前の記事
これが最強!無改造HHKB Bluetooth化 2022.05.23
-
次の記事
【Unity】TextMeshProの使い方 2022.08.17