很多时候 我们想运行一个调用一个函数 只有 在Unity 运行的时候 点击 button触发 或者 等待 那个函数 调用的上下文 触发的时候 才能 调用那个函数 , 如果调用的 场景很苛刻 ,那么 我们改如何 自己调用呢 ,显然 我们可以 直接 创建一个button 来主动触发 咱们自己的函数,但是这样还是有些麻烦 ,于是 我想到了 一种 利用 Unity 编辑器 扩展 +反射,通过类名 ,和函数名 来调用自己想触发的函数 下面 上代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System;
using System.Reflection;
public class strget
{
public string s;
public string name;
}
public class floatger
{
public float f;
public int ind => (int)f;
public uint uid => (uint)f;
public ushort usd => (ushort)f;
public short shd => (short)f;
public byte byd => (byte)f;
public Type targetType;
public string name="";
}
public class boolget
{
public bool b;
public string name = "";
}
[CustomEditor(typeof(ReflectionEditor))]
public class ReflectionEditor : EditorWindow
{
[MenuItem("MyTools/Reflection")]
public static void startReflectionEditor()
{
EditorWindow window = EditorWindow.GetWindow(typeof(ReflectionEditor));
}
string ClassDesc = "ClassName";
string ClassName;
string MethodDesc = "MethodName";
string MethodName;
List<object> Params = new List<object>();
List<object> SendData => ConversionData(Params);
public string address = "";
private void OnGUI()
{
drawContent(ClassDesc, ref ClassName);
drawContent(MethodDesc, ref MethodName);
DrawButton();
DrawParams();
}
void DrawButton()
{
EditorGUILayout.BeginHorizontal();
startBtn();
AddStrParamBtn();
AddFloatParamBtn();
autoParamButton();
resetBtn();
EditorGUILayout.EndHorizontal();
}
void AddStrParamBtn()
{
if (GUILayout.Button("AddStr"))
{
Params.Add(new strget());
}
}
void AddFloatParamBtn()
{
if (GUILayout.Button("Addfloat"))
{
Params.Add(new floatger());
}
}
void autoParam()
{
if (mod == null)
return;
Params.Clear();
foreach (var param in mod.GetParameters())
{
Debug.LogError(param.ParameterType);
if (hasType(param.ParameterType, typeof(float), typeof(int), typeof(uint), typeof(byte), typeof(ulong), typeof(short), typeof(ushort)))
{
Params.Add(new floatger() { name = param.Name, targetType = param.ParameterType });
}
else if (param.ParameterType == typeof(string))
{
Params.Add(new strget() { name = param.Name });
}
else if (hasType(param.ParameterType, typeof(bool)))
{
Params.Add(new boolget() { name = param.Name });
}
else
{
Params.Add(null);
}
}
}
void DrawParams()
{
for (byte i = 0; i < Params.Count; i++)
{
if (Params[i] is strget strget)
{
drawContent($"参数:{strget.name}{i}", ref strget.s);
}
else if (Params[i] is floatger floatger)
{
drawfloatContent($"参数:{floatger.name}{i}", ref floatger.f);
}
else if (Params[i] is boolget bl)
{
drawBoolContent($"参数:{bl.name}{i}", ref bl.b);
}
}
}
bool hasType(Type targetT, params Type[] types)
{
bool have = false;
for (int i = 0; i < types.Length; i++)
{
if (targetT == types[i])
return true;
}
return false;
}
void autoParamButton()
{
if (GUILayout.Button("autoParam"))
{
if (!tryGetMod(out mod))
{
trygetSelectMod();
};
autoParam();
}
}
void resetBtn()
{
if (GUILayout.Button("Rest"))
{
Params.Clear();
}
}
MethodInfo mod;
void startBtn()
{
if (GUILayout.Button("运行"))
{
mod = null;
if (Selection.gameObjects.IsNullOrEmpty())
{
Debug.LogError("没有选择的对象");
}
if (!tryGetMod(out mod))
{
var v = trygetSelectMod();
if (v ==null)
return;
if (Params.Count == 0 || Params == null)
{
mod.Invoke(v, null);
}
else
mod.Invoke(v, SendData.ToArray());
}
else
{
if (Params.Count == 0 || Params == null)
{
mod.Invoke(null, null);
}
else
mod.Invoke(null, SendData.ToArray());
}
}
}
MonoBehaviour trygetSelectMod()
{
if (Selection.gameObjects.IsNullOrEmpty())
{
Debug.LogError("没有当前选择的物体");
return null;
}
var target = Selection.gameObjects[0];
var v = target.GetComponent(ClassName) as MonoBehaviour;
if (v == null)
{
Debug.LogError($"选择的对象{v.name}没有继承于MonBehaviour");
return null;
}
var t = v.GetType();
mod = t.GetMethod(MethodName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static);
return v;
}
bool tryGetMod(out MethodInfo mod)
{
var tAsb = Assembly.Load("Assembly-CSharp");
Type type = tAsb.GetType(ClassName);
mod = null;
if (type == null)
return false;
mod = type.GetMethod(MethodName, BindingFlags.Public | BindingFlags.Static );
return mod != null;
}
void drawContent(string desc, ref string content)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(desc, GUILayout.Width(100));
content = EditorGUILayout.TextArea(content);
EditorGUILayout.EndHorizontal();
}
void drawfloatContent(string desc, ref float content)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(desc, GUILayout.Width(100));
content = EditorGUILayout.FloatField(content);
EditorGUILayout.EndHorizontal();
}
void drawBoolContent(string desc, ref bool content)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(desc, GUILayout.Width(100));
content = EditorGUILayout.ToggleLeft(desc,content);
EditorGUILayout.EndHorizontal();
}
List<object> ConversionData(List<object> l)
{
if (l.IsNullOrEmpty())
return null;
List<object> m_l = new List<object>();
for (int i = 0; i < l.Count; i++)
{
if (l[i] is strget strget)
{
m_l.Add(strget.s);
}
else if (l[i] is floatger floatger)
{
if (istype(typeof(float)))
{
m_l.Add(floatger.f);
}
else if (istype(typeof(byte)))
{
m_l.Add(floatger.byd);
}
else if (istype(typeof(int)))
{
m_l.Add(floatger.ind);
}
else if (istype(typeof(uint)))
{
m_l.Add(floatger.uid);
}
else if (istype(typeof(short)))
{
m_l.Add(floatger.shd);
}
else if (istype(typeof(ushort)))
{
m_l.Add(floatger.usd);
}
bool istype(Type type)
{
return floatger.targetType == type;
}
}
else if (l[i] is boolget boolget)
{
m_l.Add(boolget.b);
}
else
{
m_l.Add(null);
}
}
return m_l;
}
}
效果就是 填上类名 和 函数名 就可以调用类里的函数了 ,如果是Unity 里对象的组件自定义 脚本 非静态函数 则需要点击那个对象 在执行就可以了
例子
点击运行
非常滴方便 肯定还有很多提升空间 还请大佬指教