如何在Unity Editor Script中将Persistent Listener添加到Button.onClick事件

时间:2016-11-17 12:37:14

标签: c# unity3d

我想做一件简单的事情:

  1. 制作新的GameObject
  2. 向游戏对象添加Button组件。
  3. 向按钮的onClick事件添加持久监听器。
  4. 我尝试注册的方法是在其他一些脚本中。这是我正在尝试的一段代码:

    MyScript myScriptInstance = FindObjectOfType<MyScript>(); 
    var go = new GameObject();
    var btn = go.AddComponent<Button>();
    
    var targetinfo = UnityEvent.GetValidMethodInfo(myScriptInstance,
    "OnButtonClick", new Type[]{typeof(GameObject)});
    
    var action = (UnityAction) Delegate.CreateDelegate(typeof(UnityAction),go, targetinfo, false);
    UnityEventTools.AddPersistentListener(btn.onClick, action);
    

    MyScript.cs看起来像这样:

    public class MyScript : MonoBehaviour
    {
        public void OnButtonClick(GameObject sender)
        {
            // do some stuff here.
        }
    }
    

    当我运行此代码时,按钮Onclick监听器是空的,如下所示:

    enter image description here

    如果我改变了行

    var action = (UnityAction) Delegate.CreateDelegate(typeof(UnityAction),
    go, targetinfo, false);
    

    var action = (UnityAction) Delegate.CreateDelegate(typeof(UnityAction),
    go, targetinfo, true);
    

    我明白了:

      

    ArgumentException:方法参数长度不匹配   System.Delegate.CreateDelegate(System.Type类型,System.Object   firstArgument,System.Reflection.MethodInfo方法,布尔值   throwOnBindFailure)

    我跟着these instructions,但不知道这里出了什么问题。

    真正感谢任何形式的帮助。

3 个答案:

答案 0 :(得分:4)

花了这么多时间后,我得出结论,这是一个错误。这是一个单声道的bug。

以下是参考资料:

Ref 1Ref 2Ref 3  和Ref 4

Unity不会很快解决这个问题。他们通常不会修复与Mono相关的内容,因为他们已经在努力升级到最新的Mono运行时。

幸运的是,还有另外两种解决方法:

1 。使用通用参数AddObjectPersistentListenerUnityAction,然后将通用内容传递给Delegate.CreateDelegate函数。

MyScript myScriptInstance = FindObjectOfType<MyScript>();
var go = new GameObject();
var btn = go.AddComponent<Button>();

var targetinfo = UnityEvent.GetValidMethodInfo(myScriptInstance,
"OnButtonClick", new Type[] { typeof(GameObject) });

UnityAction<GameObject> action = Delegate.CreateDelegate(typeof(UnityAction<GameObject>), myScriptInstance, targetinfo, false) as UnityAction<GameObject>;

UnityEventTools.AddObjectPersistentListener<GameObject>(btn.onClick, action, go);

2 。根本不使用Delegate.CreateDelegate。只需使用AddObjectPersistentListener

MyScript myScriptInstance = FindObjectOfType<MyScript>();
var go = new GameObject();
var btn = go.AddComponent<Button>();

UnityAction<GameObject> action = new UnityAction<GameObject>(myScriptInstance.OnButtonClick);
UnityEventTools.AddObjectPersistentListener<GameObject>(btn.onClick, action, go);

如果这些都给你这个:

enter image description here

第二种解决方案不需要使用反射来查找函数。您必须在运行时绑定该函数。第一个使用反射。

您可能需要使用第一个解决方案,因为它与您正在执行的操作非常相似,您可以将函数名称作为字符串变量提供。

答案 1 :(得分:0)

也许我没有理解你的问题,但是Button脚本公开了onClick事件,你可以add listeners to(在代码中)。

这是我使用的代码:

// Use this for initialization
void Start () {

    MyScript myScriptInstance = FindObjectOfType<MyScript> ();

    GameObject go = DefaultControls.CreateButton (new DefaultControls.Resources());
    var btn = go.GetComponent<Button> ();

    btn.onClick.AddListener (myScriptInstance.TestMethod);
}

这里是MyScript.TestMethod的代码:

public void TestMethod ()
{
    Debug.Log ("TestMethod");   
}

有几点需要注意:

  1. 您手动创建GameObject并向其添加Button组件。 UI元素有点不同,因为它们具有RectTransform并且必须存在于要呈现的Canvas对象下。
  2. 在我的示例中,我创建按钮的方式与从UI菜单项本身创建的方式类似(请参阅参考here)。这将成功创建它,但不会在画布下添加它。
  3. 最后一件事 - 就我而言,我定义的TestMethod只是打印一个日志。单击按钮时,它会记录消息,但在Button的检查器中,我看不到列出的任何onClick事件。这可能只意味着在运行时向其添加侦听器时不会刷新检查器。

答案 2 :(得分:-1)

因为我无法发表评论,非常感谢@Programmer的回答! 我在第二个示例中编辑了您的代码,以在编辑器中也填充UnityEvents。 将代码复制并粘贴到2个单独的脚本中,一个名为Menu,一个名为MyScript。 确保“菜单”脚本位于名为“编辑器”的文件夹中。

%timeit