Unityでゲームを作っていると、GameObjectにComponentを沢山、ぶらさげていくことになります。この時に、コンポーネント同士でお互いの機能を使うために参照するなど、「互いに必須のコンポーネント」が要るようになります。そうした場合の方法を考えてみましょう。
コンポーネントを必須化するRequire Component
UnityEngineで用意された、Require Componentを使うと、同じGameObjectでアタッチされたコンポーネントをチェックして、それがないとビルドでエラーになるようにできます。
例えば、以下のコードがあったとします。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestClassA : MonoBehaviour {
[SerializeField]
TestClassB testClassB;
[SerializeField]
TestClassC testClassC;
private void Start()
{
testClassB = GetComponent<TestClassB>();
testClassC = GetComponent<TestClassC>();
}
}
TestClassAというコンポーネントから、TestClassB,TestClassCを参照しているとします。ただし、GameObjectにアタッチされているかは判りませんから、場合によってはGetComponentが失敗することがあります。それを防ぐために、以下の形にします。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//必要なコンポーネントを定義
[RequireComponent(typeof(TestClassB))]
[RequireComponent(typeof(TestClassC))]
public class TestClassA : MonoBehaviour {
[SerializeField]
TestClassB testClassB;
[SerializeField]
TestClassC testClassC;
private void Start()
{
testClassB = GetComponent<TestClassB>();
testClassC = GetComponent<TestClassC>();
}
}
TestClassAをアタッチすると、Require Componentで指定されたコンポーネントTestClassB、TestClassCが自動的にアタッチされます。


また、指定されアタッチされたコンポーネントは外せません。この例の場合では、TestClassAを外さないままでTestClassBを外そうとすると、エラーになります。
書式は以下になります。
[RequireComponent(typeof(追加したいコンポーネント名))]
初期化をしてくれるReset()
上記でコンポーネントの追加を自動化できましたが、Start()でGetComponentするまで、参照は入りません。初期化で負荷がかかるので、同様のGameObjectが多い場合には、起動前に代入しておきたいものです。その時にEditor上で実行できるメソッドがReset()です。
前記コードを以下に変更します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//必要なコンポーネントを定義
[RequireComponent(typeof(TestClassB))]
[RequireComponent(typeof(TestClassC))]
public class TestClassA : MonoBehaviour {
[SerializeField]
TestClassB testClassB;
[SerializeField]
TestClassC testClassC;
private void Reset()
{
testClassB = GetComponent<TestClassB>();
testClassC = GetComponent<TestClassC>();
}
}
これを実行すると、コンポーネント追加やギアアイコンからResetしたときに、Reset()が実行されます。
同じようにTestClassAだけ追加していますが、今度はTestClassB、TestClassCが自動的にアタッチされると同時に、参照の代入も実行されます。
使い方のあれこれ
-
Require Componentだけの場合、必須にしたいものはRigidbody等でも使えます。特定の初期化する部分をReset()に書くことも可能です。 - 最初のサンプルから入れてあるので触れていませんが、
[SerializeField]はReset()で設定したい場合は必須です。RequireComponentは[SerializeField]が無くとも有効です。 - SceneでStaticなどで保証されるものなら、Resetで
find等を用いて検索することも可能です。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(TestClassB))]
[RequireComponent(typeof(TestClassC))]
[RequireComponent(typeof(Rigidbody))]
public class TestClassA : MonoBehaviour
{
[SerializeField]
TestClassB testClassB;
[SerializeField]
TestClassC testClassC;
[SerializeField]
Rigidbody rigidBody;
[SerializeField]
GameController gameController;
[SerializeField]
TestEnemy testEnemy;
private void Reset()
{
testClassB = GetComponent<TestClassB>();
testClassC = GetComponent<TestClassC>();
rigidBody = GetComponent<Rigidbody>();
gameController = FindObjectOfType<GameController>();
if (gameController == null) {
Debug.Log("ERROR!Gamecontroller not found");
}
}
}
必須になるものをGameControllerにいろいろ記述して参照できるようにしておくと、Scene内での相互参照したいGameObject同士のアクセスが楽になります。そうした場合に、上記方法を使うと便利ですね。

