如何在代码中正确实现Unity按钮的onClick事件?

问题描述 投票:0回答:2

我正在尝试将事件添加到运行时组装的菜单上的按钮。

// The rest of the menu is assembled around this. There is a 'foreach' loop adding the buttons one at a time.

GameObject obj = Instantiate(quickCommandPrefab, FindCorrectHolder(c.cType).transform);

// >>>
// There are other things happening here that aren't having problems.
// >>>

//  set the event for the "button press"
btn = obj.transform.GetComponent<Button>();
btn.onClick.RemoveAllListeners();
btn.onClick.AddListener(delegate { CheckKeyPress(c.keyToActivate); });
//  There is just something about the button onClick event.

我尝试了多种略有不同的语法,但仍然达到了这个效果。

这些是被实例化的对象的组件。

enter image description here

我什至将该代码分离到自己的函数中,以便在实例化后单独执行,如下所示:

void SetupButtonEvents()
{
    foreach (Button btn in transform.GetComponentsInChildren<Button>(true))
    {
        Button temp = btn;  // I did try a temp variable as well to see if that would help. NOPE, same problem!
        
        string keyCode = btn.transform.Find("UseKeyText").GetComponent<TextMeshProUGUI>().text;
        btn.onClick.RemoveAllListeners();
        btn.onClick.AddListener(delegate { CheckKeyPress(Enum.Parse<KeyCode>(keyCode)); });
    }
}

我一直在使用“Debug.LogWarnings”来跟踪正在发生的事情,并且

btn.onClick.GetPersistentEventCount()
总是会回来
0

我不能说,因为我以前遇到过这个问题,尽管这通常没有 Unity 自己的事件系统,或者通过检查器而不是通过代码使用所述事件系统。

c# unity-game-engine events delegates
2个回答
1
投票

当您查看

onClick
类型
UnityEvent
的参考文档时:

  • AddListener
    :向 UnityEvent 添加非持久监听器。
  • GetPersistentEventCount
    :获取已注册持久监听的数量。

GetPersistentEventCount
不会返回您使用
AddListener
添加的听众的计数。一个处理“持久”侦听器,另一个则不处理。因此该方法不足以验证是否已添加侦听器。


0
投票
c

foreach
循环变量,则每个匿名委托将捕获相同的变量,因此每个回调将引用相同的变量,该变量将包含最后分配的数据,而不是您期望的数据。
你的第二个代码片段中也有一些有问题的东西。不要从 

TextMeshPro

组件读回文本值。这些是用于可视化文本的组件,它们通常会向文本添加不可见的格式字符。这些额外的字符会扰乱您的枚举文本解析。另外,您不应该将

Enum.Parse
调用放在回调中。这意味着您每次按下按钮时都会解析它。在委托外部解析它,将实际的关键代码保存在局部变量中,并让委托捕获该变量。尽管正如我所说,不要使用
TextMeshPro
组件来存储和读回数据。您可以使用按钮的游戏对象名称,只要您在生成代码中重命名它即可。
因此,假设第一个代码片段位于 

foreach

循环中,您应该使用额外的局部变量

KeyCode key = c.keyToActivate;
btn.onClick.AddListener(delegate { CheckKeyPress(key); });

这应该修复第一个代码片段。要调试该问题,您还可以在委托内部添加一个 
Debug.Log("Button pressed with key " + key)

调用来查看实际使用的值。

正如其他人已经解释的那样,

UnityEvents

拥有持久且动态的订阅者。持久订阅者是在检查器中序列化的订阅者。动态监听器是在运行时添加的附加监听器。所以你的听众不能出现在检查器中。

    

© www.soinside.com 2019 - 2024. All rights reserved.