【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 にキャストして返します。






ディスカッション
コメント一覧
まだ、コメントがありません