LoginSignup
0
0

【Unity】文字列でGameObject, Component, 関数名, 引数を指定して関数を実行する

Posted at

Reflectionを使って文字列から関数を実行する

まずは具体例から

Playerクラス
class Player
{
    public void Attack(string name, int atk)
    {
        Debug.Log($"{name} は {atk} のダメージを与えた!");
    }
}

このAttack関数を実行したいとき、普段ならこのように書きます

普段の書き方
Player player = new Player();
player.Attack("田中", 30);

今回は
・関数を実行するインスタンス
・実行する関数名
・引数のstring配列
の3つを使って実行してみます

Attackを実行
// リフレクションを使って関数を呼び出す
public void CallFunction()
{
    Player player = new Player(); // 関数を実行したいインスタンス
    string[] parameters = new string[] { "田中", "30" }; // 引数の文字列
    string methodName = "Attack"; //実行したい関数名

    // playerの型情報typeを取得
    Type type = player.GetType();
    // PlayerクラスのAttack関数の情報を取得
    MethodInfo method = type.GetMethod(methodName);

    // Attack関数の引数情報を取得
    ParameterInfo[] paramInfos = method.GetParameters();

    // parametersの型をstringから引数の型に直したモノを入れる配列
    object[] typedParameters = new object[parameters.Length];

    // 引数情報paranInfosで取得した型にparametersを変換
    for (int i = 0; i < parameters.Length; i++)
    {
        typedParameters[i] = Convert.ChangeType(parameters[i], paramInfos[i].ParameterType);
    }

    // 関数を実行
    method.Invoke(player, typedParameters);
}

上の具体例のインスタンス, methodName, parametersを引数に変えたものがこちら

引数にチェンジ
// リフレクションを使って関数を呼び出す
void CallFunctionByMethodName(object obj, string methodName, string[] parameters)
{
    // objの型情報typeを取得
    Type type = obj.GetType();
    // objのクラスの名前が methodName の関数の情報を取得する
    MethodInfo method = type.GetMethod(methodName);

    if (method != null)
    {
        ParameterInfo[] paramInfos = method.GetParameters();

        if (parameters != null && parameters.Length >= 1)
        {
            object[] typedParameters = new object[parameters.Length];

            for (int i = 0; i < parameters.Length; i++)
            {
                typedParameters[i] = 
                    Convert.ChangeType(parameters[i], paramInfos[i].ParameterType);
            }

            method.Invoke(obj, typedParameters);

        }
        else
        {
            method.Invoke(obj, null);
        }
    }
}

GameObjectの名前とコンポーネントも文字列で指定する

さらにGameObjectの名前とコンポーネントも文字列で指定して関数を呼び出すように変更します。

文字列からGameObjectを取得するにはGameObject.Find(string name)を利用します。

GameObject gameObject = GameObject.Find(gameObjectName);

文字列からコンポーネントを取得するにはComponent GetComponent(string type)を利用します。

gameObject.GetComponent(componentName);

呼び出したいときに渡す情報をクラスにまとめておきます。

class FunctionByString
{
    public string GameObjectName { get; set; }
    public string ComponentName { get; set; }
    public string FunctionName { get; set; }
    public string[] Parameters { get; set; }
}

上のFunctionByStringを渡して実行するプログラムがこちら

void CallFunctionBy(FunctionByString functionByString)
{
    // 文字列からGameObjectを取得
    GameObject targetObject = GameObject.Find(functionByString.GameObjectName);
    if (targetObject != null)
    {
        // 文字列からコンポーネントを取得
        Component targetComponent =
            targetObject.GetComponent(functionByString.ComponentName);
        if (targetComponent != null)
        {
            // さっき作った関数に渡す
            CallFunctionByMethodName(
                targetComponent, 
                functionByString.FunctionName, 
                functionByString.Parameters);
        }
    }
}

何が嬉しいか

CSVなどで関数の実行を制御できる

イベントシーンの動きをCSVなどで制御できます

問題点

GameObject.FindやGetComponentを毎回行っている

重めの処理なのでよく使うコンポーネントはDictionaryとかにまとめておいた方がよいかも

参考文献

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0