C#
Unity
Unity入門
UnityEditor

[Unity初心者Tips]確実に!必要なComponentを入れるRequire ComponentとReset()

More than 1 year has passed since last update.

Unityでゲームを作っていると、GameObjectにComponentを沢山、ぶらさげていくことになります。この時に、コンポーネント同士でお互いの機能を使うために参照するなど、「互いに必須のコンポーネント」が要るようになります。そうした場合の方法を考えてみましょう。


コンポーネントを必須化するRequire Component

UnityEngineで用意された、Require Componentを使うと、同じGameObjectでアタッチされたコンポーネントをチェックして、それがないとビルドでエラーになるようにできます。

例えば、以下のコードがあったとします。


TestClassA.cs

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が失敗することがあります。それを防ぐために、以下の形にします。


TestClassA.cs

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で指定されたコンポーネントTestClassBTestClassCが自動的にアタッチされます。

https://gyazo.com/93f9c5862fb6502eef72b89f6ed2bb8f

https://gyazo.com/4fa4e60f51ecc5c9e3f6fca7328c74f2

また、指定されアタッチされたコンポーネントは外せません。この例の場合では、TestClassAを外さないままでTestClassBを外そうとすると、エラーになります。

書式は以下になります。


[RequireComponent(typeof(追加したいコンポーネント名))]



初期化をしてくれるReset()

上記でコンポーネントの追加を自動化できましたが、Start()でGetComponentするまで、参照は入りません。初期化で負荷がかかるので、同様のGameObjectが多い場合には、起動前に代入しておきたいものです。その時にEditor上で実行できるメソッドがReset()です。

前記コードを以下に変更します。


TestClassA.cs

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()が実行されます。

https://gyazo.com/e3eaebcc90a4b96eb852a367e8a77a8d

https://gyazo.com/246ea789115a9bcdde172ee1a3063f3b

同じようにTestClassAだけ追加していますが、今度はTestClassBTestClassCが自動的にアタッチされると同時に、参照の代入も実行されます。


使い方のあれこれ



  • Require Componentだけの場合、必須にしたいものはRigidbody等でも使えます。特定の初期化する部分をReset()に書くことも可能です。

  • 最初のサンプルから入れてあるので触れていませんが、[SerializeField]Reset()で設定したい場合は必須です。RequireComponent[SerializeField]が無くとも有効です。

  • SceneでStaticなどで保証されるものなら、Resetでfind等を用いて検索することも可能です。


TestClassA.cs

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同士のアクセスが楽になります。そうした場合に、上記方法を使うと便利ですね。


参考