You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中重现Button组件On Click()功能的技术问询

实现Unity Button「On Click()」类似功能的方案

1. 定义可序列化的调用数据结构

先做一个能在Inspector里保存调用信息的类,用来存目标对象、要调用的方法名:

[System.Serializable]
public class MethodCall
{
    public UnityEngine.Object target;
    public string methodName;
}

public class CustomButton : MonoBehaviour
{
    public List<MethodCall> functionArray = new List<MethodCall>();
    public bool callFunctions;

    void Update()
    {
        // 这里用Update做触发示例,实际可绑定到自定义点击/触发逻辑
        if (callFunctions)
        {
            foreach (var call in functionArray)
            {
                if (call.target == null || string.IsNullOrEmpty(call.methodName))
                    continue;
                
                // 用反射调用目标方法
                call.target.GetType().InvokeMember(
                    call.methodName,
                    System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance,
                    null,
                    call.target,
                    null
                );
            }
            callFunctions = false; // 避免单次触发重复调用
        }
    }
}

2. 编写编辑器扩展实现Inspector选择界面

Unity默认List没法直接选脚本和方法,得自定义编辑器来实现类似Button的选择逻辑:

#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;

[CustomEditor(typeof(CustomButton))]
public class CustomButtonEditor : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        CustomButton customBtn = (CustomButton)target;

        EditorGUILayout.Space();
        EditorGUILayout.LabelField("Method Calls", EditorStyles.boldLabel);

        // 遍历所有调用项
        for (int i = 0; i < customBtn.functionArray.Count; i++)
        {
            EditorGUILayout.BeginHorizontal();
            
            // 选择目标对象
            customBtn.functionArray[i].target = EditorGUILayout.ObjectField("Target", customBtn.functionArray[i].target, typeof(UnityEngine.Object), true);
            
            // 有目标对象时,显示脚本和方法选择
            if (customBtn.functionArray[i].target != null)
            {
                MonoBehaviour[] scripts = customBtn.functionArray[i].target.GetComponents<MonoBehaviour>();
                if (scripts.Length > 0)
                {
                    // 选择挂载的脚本
                    int scriptIndex = EditorGUILayout.Popup("Script", 0, scripts.Select(s => s.GetType().Name).ToArray());
                    MonoBehaviour selectedScript = scripts[scriptIndex];

                    // 筛选出无参、返回值为void的公共方法,和Button的OnClick逻辑对齐
                    List<MethodInfo> validMethods = selectedScript.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance)
                        .Where(m => m.GetParameters().Length == 0 && m.ReturnType == typeof(void))
                        .ToList();
                    
                    if (validMethods.Count > 0)
                    {
                        // 选择要调用的方法
                        int methodIndex = EditorGUILayout.Popup("Method", 0, validMethods.Select(m => m.Name).ToArray());
                        customBtn.functionArray[i].methodName = validMethods[methodIndex].Name;
                    }
                    else
                    {
                        EditorGUILayout.LabelField("无符合要求的方法");
                    }
                }
                else
                {
                    EditorGUILayout.LabelField("未挂载脚本");
                }
            }

            // 删除当前调用项
            if (GUILayout.Button("-", GUILayout.Width(20)))
            {
                customBtn.functionArray.RemoveAt(i);
                i--;
            }
            EditorGUILayout.EndHorizontal();
        }

        // 添加新的调用项
        if (GUILayout.Button("添加方法调用"))
        {
            customBtn.functionArray.Add(new MethodCall());
        }

        // 标记对象修改,确保数据能保存
        if (GUI.changed)
        {
            EditorUtility.SetDirty(customBtn);
        }
    }
}
#endif

3. 关键细节说明

  • 反射调用前必须做空值判断,避免空引用报错
  • 编辑器里过滤的方法规则和Unity Button一致:只显示无参、返回值为void的公共方法
  • 可以把触发逻辑从Update改成自定义的点击检测(比如OnMouseDown),更贴近Button的使用场景
  • 用EditorUtility.SetDirty确保修改的配置能保存到场景或预制体中

内容的提问来源于stack exchange,提问作者Aliph Null

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 01:55:17