Unityでクラスのインスタンス化を行うとき、エラーが起きて困ったことはないでしょうか。
私もWeb開発などを行っていてその後にUnityで開発となった時に
クラスのインスタンス化でエラーが出て困惑したことがあります。
今回はUnityでのクラスのインスタンス化について解説していきたいと思います。
Unityのクラスのインスタンス化は他のプログラミングとは違う
コンソールアプリでインスタンス化を確認してみる
Unityのインスタンス化と比較するためにまずは普通のC#のコンソールアプリで確認してみます。
Personクラスがあり、インスタンス化してそれぞれの値をログ出力します。
public class Person
{
public string Name;
public int Age;
public string Prefecture;
public string Hobby;
}
class Program
{
static void Main(string[] args)
{
// Personクラスのインスタンス化
Person p1 = new Person();
Person p2 = new Person();
Person p3 = new Person();
p1.Name = "Taro";
p2.Name = "Jiro";
p3.Name = "Hanako";
p1.Age = 25;
p2.Age = 26;
p3.Age = 27;
p1.Prefecture = "Tokyo";
p2.Prefecture = "Osaka";
p3.Prefecture = "Nagoya";
p1.Hobby = "Soccer";
p2.Hobby = "Baseball";
p3.Hobby = "Basketball";
Console.WriteLine(p1.Name + " " + p1.Age + " " + p1.Prefecture + " " + p1.Hobby);
Console.WriteLine(p2.Name + " " + p2.Age + " " + p2.Prefecture + " " + p2.Hobby);
Console.WriteLine(p3.Name + " " + p3.Age + " " + p3.Prefecture + " " + p3.Hobby);
}
}
実行結果

クラス変数型の次に変数名を定義し、その後newすることでインスタンスを生成できます。
各々のインスタンスで変数にアクセスし、ログに出力できています。
何ら問題ないと思います。
Unityでのインスタンス化
ではUnityでインスタンス化するとどうなるか見ていきましょう。
ClassAとClassBがあり、ClassAをインスタンス化し、ClassBで使いたいとします。
【ClassA.cs】
using UnityEngine;
public class ClassA : MonoBehaviour
{
// この値をClassBで使いたい。
public int num1 = 120;
void Start()
{
}
}
【ClassB.cs】
using UnityEngine;
public class ClassB : MonoBehaviour
{
// ★クラスAのインスタンス化を生成
ClassA classA = new ClassA();
void Start()
{
// インスタンス化したclassAの変数num1をログ出力
Debug.Log(classA.num1);
}
}
ログ出力のため、適当にオブジェクトを作成し、アタッチします。

この状態で再生を押すと下記のような警告が出ます。

You are trying to create a MonoBehaviour using the 'new' keyword.
This is not allowed. MonoBehaviours can only be added using AddComponent().
Alternatively, your script can inherit from ScriptableObject or no base class at all
UnityEngine.MonoBehaviour:.ctor ()
上記の意味は
newをしてMonoBehaviourを作成しようとしています。これは禁止されています。
MonoBehavioursは、AddComponent()を使用してのみ追加できます。
別の方法として、スクリプトは ScriptableObject を継承するか、基本クラスを継承しないこともできます。
という意味です。
色々と書かれていますが、
つまりMonoBehaviourを継承したクラスをインスタンス化するのは禁止されている
ということです。
普通のプログラミングだとインスタンス化のため、newしますが、
UnityではMonoBehaviourを継承したクラスはインスタンス化が禁止されています。
クラス型変数とprivateを使ってみる
「インスタンス化できないのならクラス型変数を使ってprivateにして値を受け渡そう。
privateにすると他のクラスからアクセスできないので安全だ。」
ではやってみましょう。
【ClassB】
using UnityEngine;
public class ClassB : MonoBehaviour
{
// クラス型変数を用紙し、privateで他のクラスからのアクセスを制限
private ClassA classA;
void Start()
{
Debug.Log(classA.num1);
}
}
こちらで再生を押すと次のようになります。

NullReferenceExceptionエラーが出ます。どうしてでしょうか。
それはクラス型の変数、classAに値が入っていないからです。
クラスを利用するにはインスタンス化を必ず行う必要があります。
クラス型の変数を定義しただけでは値を利用することができないのです。
ではMonoBehaviourを継承したクラスではどのようにインスタンス化できるのでしょうか。
エディタからアタッチすることでインスタンス化できる
下記のようにコードを変更しましょう。
using UnityEngine;
public class ClassB : MonoBehaviour
{
// ★SerializeField属性を付与
[SerializeField] private ClassA classA;
void Start()
{
Debug.Log(classA.num1);
}
}
SerializeField属性を付与することでエディタで変数の値を確認できるようになります。
属性を付与した変数がクラス型であった場合、そのクラスのスクリプトがアタッチされている
オブジェクトをアタッチすることでインスタンス化を行うことができます。
何言ってんだお前、ってなるので画像で確認しましょう。
上記のように修正してインスペクタを見ると画像のようになります。

今の状態では利用したいClassAがアタッチされているオブジェクトがないので
新たにオブジェクトを作成し、ClassAをアタッチします。

今回はClassAObjectを作成し、ClassAスクリプトをアタッチしました。
では、CubeオブジェクトにClassAObjectをアタッチしてみます。

こちらで再生を押すと、変数の値がログに出力されます。
今回は120と値を入れていたので「120」と表示されます。

つまり、UnityでMonoBehaviourを継承したクラスは
クラス型の変数を用意し、SerializeField属性を付与し、
エディタからスクリプトをアタッチすることでインスタンス化することができます。
まとめ
いかがだったでしょうか。
Unityでのインスタンス化は他のプログラミングとは違うことが分かったと思います。
クラス型の変数を用意し、SerializeField属性を付与し、
エディタからスクリプトをアタッチすることでインスタンス化することができる
のがUnityの特徴だと覚えてもらうと良いと思います。
コメント