我正在尝试将事件添加到运行时组装的菜单上的按钮。
// 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.
我尝试了多种略有不同的语法,但仍然达到了这个效果。
这些是被实例化的对象的组件。
我什至将该代码分离到自己的函数中,以便在实例化后单独执行,如下所示:
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 自己的事件系统,或者通过检查器而不是通过代码使用所述事件系统。
当您查看
onClick
类型 UnityEvent
的参考文档时:
AddListener
:向 UnityEvent 添加非持久监听器。GetPersistentEventCount
:获取已注册持久监听的数量。GetPersistentEventCount
不会返回您使用 AddListener
添加的听众的计数。一个处理“持久”侦听器,另一个则不处理。因此该方法不足以验证是否已添加侦听器。
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
拥有持久且动态的订阅者。持久订阅者是在检查器中序列化的订阅者。动态监听器是在运行时添加的附加监听器。所以你的听众不能出现在检查器中。