【Unity】ゲームオブジェクトとコンポーネントの操作をスクリプトでシミュレート
Unityエディターで初期のシーンを構成し、実行(Playボタン)するとアタッチされているスクリプトが実行され、他のゲームオブジェクトにアタッチされているスクリプトが実行されるケースを考えてみます
シーン構成
2つのゲームオブジェクトを作成して、一方のスクリプトを実行して他方のスクリプトにアクセスするケースになります
イメージ
GemeObjectという名前のゲームオブジェクトにアタッチされているスクリプト内から、Playerという名前のゲームオブジェクトにアタッチされているShowMessageスクリプトのShowHelloメソッドにアクセス
他のゲームオブジェクトにアクセスする側
空のゲームオブジェクトの作成します(名前はデフォルトのGameObjectのまま)
using UnityEngine;
public class Manager : MonoBehaviour
{
void Start()
{
GameObject obj = GameObject.Find("Player");
ShowMessage showMessage = obj.GetComponent<ShowMessage>();
showMessage.ShowHello();
}
}
GameObject obj = GameObject.Find("Player");
GameObject.Find()
は、名前がPlayer
のゲームオブジェクトを検索して取得します。そのオブジェクトをobj
変数に代入します。
ShowMessage showMessage = obj.GetComponent<ShowMessage>();
obj
変数が参照するゲームオブジェクトにアタッチされているShowMessage
コンポーネントを取得し、showMessage
変数に代入します。
showMessage.ShowHello();
ShowMessage
コンポーネントのShowHello()
メソッドを呼び出します。このメソッドは、"Hello!"
という文字列をデバッグログに出力するものと仮定されます。
アクセスされる側
空のゲームオブジェクトをもう1つ作成します(名前をPlayer)とします
using UnityEngine;
public class ShowMessage : MonoBehaviour
{
public void ShowHello()
{
Debug.Log("Hello");
}
}
ShowHelloという公開されたメソッドは、このクラスに定義されています。このメソッドは、UnityのDebugクラスを使用して、"Hello"というメッセージをコンソールにログとして出力します。
このスクリプトは、Unityのゲームオブジェクトにアタッチされ、オブジェクトがアクティブ化されたときに、ShowHelloメソッドが呼び出されます。このスクリプトがアタッチされたオブジェクトを実行すると、"Hello"というメッセージがコンソールに表示されます。
実行結果
Hello
Playerゲームオブジェクト作成とスクリプトアクセス(コンポーネントアクセス)のシミュレート
通常は、プログラマーはゲームオブジェクトを直接作成することはありません(Instantiateメソッドを使って作成)
今回は、内部の動作を学習するためにあえて作成してみます
準備
上記で作成したシーンからPlayerゲームオブジェクトを削除します
Managerスクリプトの更新で、同様な結果(Helloと表示)を得るようにします
ゲームオブジェクトをNewキーワードで作成
テストコード
using UnityEngine;
public class Manager : MonoBehaviour
{
void Start()
{
GameObject obj = new GameObject();
}
}
実行結果
ヒエラルキーウィンドウに New Game Objectという名前のゲームオブジェクトが作成されています(コンポーネントはTransformだけ作成されています)
作成されたゲームオブジェクトの名前をPlayerに変更
テストコード
using UnityEngine;
public class Manager : MonoBehaviour
{
void Start()
{
GameObject obj = new GameObject();
obj.name = "Player";
}
}
実行結果
ヒエラルキーウィンドウに New Game Objectという名前がPlayerに変更されています
PlayerゲームオブジェクトにコンポーネントとしてのShowMessageスクリプトを追加
テストコード
using UnityEngine;
public class Manager : MonoBehaviour
{
void Start()
{
GameObject obj = new GameObject();
obj.name = "Player";
obj.AddComponent<ShowMessage>();
}
}
実行結果
Playerゲームオブジェクトにコンポーネントが追加されました
Playerゲームオブジェクトにアタッチされたコンポーネント(ShowMessageスクリプト)の参照を取得し、ShowHelloメソッドを実行
テストコード
using UnityEngine;
public class Manager : MonoBehaviour
{
void Start()
{
GameObject obj = new GameObject();
obj.name = "Player";
obj.AddComponent<ShowMessage>();
ShowMessage showMessage = obj.GetComponent<ShowMessage>();
showMessage.ShowHello();
}
}
実行結果
実行前は、GameObjectしかありませんが、実行すると、Playerゲームオブジェクトが作成され、コンポーネントが追加され、さらに実行されることでHelloと表示されるのがわかります
おまけ
推奨するわけでありませんが、同じコードになります
using UnityEngine;
public class Manager : MonoBehaviour
{
void Start()
{
GameObject player = new GameObject("Player");
player.AddComponent<ShowMessage>().ShowHello();
}
}
using UnityEngine;
public class Manager : MonoBehaviour
{
void Start()
{
new GameObject("Player", typeof(ShowMessage))
.GetComponent<ShowMessage>()
.ShowHello();
}
}
C#コードでシミュレートしたら・・・
違いを見比べてみましょう
シンプルなサンプル
using UnityEngine;
public class Manager : MonoBehaviour
{
void Start()
{
GameObject obj = new GameObject();
obj.name = "Player";
obj.ShowHello();
}
}
class GameObject
{
public string name;
public void ShowHello()
{
Debug.Log("Hello");
}
}
コンポーネントのシミュレートを追加すると・・・
難しいですが、もう少し、テストコードに近づけてみましょう
using System.Collections.Generic;
using UnityEngine;
public class Manager : MonoBehaviour
{
void Start()
{
GameObject obj = new GameObject();
obj.name = "Player";
obj.AddComponent<ShowMessage2>();
ShowMessage2 showMessage2 = obj.GetComponent<ShowMessage2>();
showMessage2.ShowHello();
}
}
class GameObject
{
List<Component> components = new List<Component>();
public string name { get; set; }
public T AddComponent<T>() where T : Component, new()
{
T component = new T();
components.Add(component);
return component;
}
public T GetComponent<T>() where T : Component
{
return components.Find(component => component is T) as T;
}
}
class Component { }
class ShowMessage2 : Component
{
public void ShowHello()
{
Debug.Log("Hello");
}
}
Start
メソッドは、新しいゲームオブジェクトを作成し、その名前を"Player"に設定し、ShowMessage2という新しいコンポーネントを追加し、ShowMessage2コンポーネントのShowHello
メソッドを呼び出して、"Hello"というメッセージを表示します。
GameObject
クラスはUnityで使用されるGameObjectクラスを簡略化したもので、コンポーネントを追加・削除するためのメソッドを提供しています。また、name
プロパティを持ち、GameObjectの名前を取得・設定できます。
Component
クラスはUnityで使用されるコンポーネントクラスを簡略化したもので、派生クラスに継承させるためのクラスです。
ShowMessage2
クラスは、Component
を継承しています。ShowMessage2
クラスはShowHello
メソッドを持ち、その中で"Hello"というメッセージを表示するために、UnityのDebug.Log
メソッドを使用しています。ShowMessage2
コンポーネントをGameObject
に追加し、ShowHello
メソッドを呼び出すことで、このメッセージが表示されます。
AddComponentメソッドのシミュレート解説
public T AddComponent<T>() where T : Component, new()
{
T component = new T();
components.Add(component);
return component;
}
このコードは、AddComponent
というジェネリックメソッドを定義しています。このメソッドは、指定されたジェネリック型パラメータT
を持つComponent
の派生クラスのインスタンスを作成し、List<Component>
のcomponents
に追加し、最後に作成したインスタンスを返します。
このメソッドは、型パラメータT
がComponent
の派生クラスであることを制約としているため、このメソッドを呼び出すときにT
に指定できる型はComponent
を継承している型に限定されます。また、where T : new()
という制約があるため、T
はパラメータなしのコンストラクタを持っている必要があります。
このメソッドを呼び出すことで、指定した型のComponent
を作成し、components
に追加することができます。たとえば、AddComponent<Transform>()
と呼び出すと、Transform
クラスのインスタンスが作成され、components
に追加されます。このように、ジェネリックメソッドを使用することで、コードの再利用性を高め、汎用的なコードを作成することができます。
GetComponentメソッドのシミュレート解説
public T GetComponent<T>() where T : Component
{
return components.Find(component => component is T) as T;
}
このコードは、ジェネリックメソッドの GetComponent
を定義しています。このメソッドは、指定された型 T
の Component
を検索して返します。
このメソッドは、where
キーワードを使用して型制約を設定しています。T
型は Component
クラスのサブクラスである必要があります。
Find
メソッドは、リストの要素を検索し、指定された条件に一致する最初の要素を返します。このコードでは、components
リストの要素をループして、型 T
であるコンポーネントを検索しています。一致する要素が見つかった場合、as
演算子を使用してその要素を型 T
にキャストして返します。
ディスカッション
コメント一覧
まだ、コメントがありません