我想更多地了解以下情况。我有一个简单的基类,它有一个Button类型的公共变量。在我的Start函数中,我使用Button的click事件并为其添加一个监听器。但是,代码根本不执行,并且它的唯一工作方式是将事件侦听器挂接到Awake函数而不是Start函数。
事件不会在以下内容中执行:
protected virtual void OnExitedUI()
{
if(ExitedUI != null)
{ ExitedUI(this.gameObject); }
}
[Tooltip("The Button script/GameObject this UI uses as an Exit button. Used to destroy the UI and fire the exit event.")]
public Button exitButton;
// Subscribe to our events at the start.
private void Start()
{
exitButton.onClick.AddListener(() => { OnExitClick(); });
}
// Event handler for the exit button click event.
// Fire our ExitedUI event and destroy the object.
private void OnExitClick()
{
Debug.Log("Exited UI!");
OnExitedUI();
Destroy(this.gameObject);
}
事件执行并按预期工作。请注意,唯一改变的是Start to Awake。
protected virtual void OnExitedUI()
{
if(ExitedUI != null)
{ ExitedUI(this.gameObject); }
}
[Tooltip("The Button script/GameObject this UI uses as an Exit button. Used to destroy the UI and fire the exit event.")]
public Button exitButton;
// Subscribe to our events at the start.
private void Awake()
{
exitButton.onClick.AddListener(() => { OnExitClick(); });
}
// Event handler for the exit button click event.
// Fire our ExitedUI event and destroy the object.
private void OnExitClick()
{
Debug.Log("Exited UI!");
OnExitedUI();
Destroy(this.gameObject);
}
我知道在Start函数之前调用了Awake函数。但是我不知道这会如何影响这个过程 - 事实上,我认为Start方法应该更好,因为我可以确定Button是正确初始化的,或者是在这个脚本的同时实例化的。
附加说明:上面的脚本是我用于UI GameObject的UI管理器类的基础,它包含一组面板和UI元素。其中一个子面板包括上面引用的“退出”按钮。
答案 0 :(得分:2)
在我的Start函数中,我使用Button的click事件并为其添加一个监听器。
这是解决问题的关键。
如果要执行侦听器的代码,则需要在执行事件之前添加侦听器。否则委托不能执行它,因为它不知道它必须执行什么。
当您添加侦听器并在Start()
中执行时,您无法保证首先调用添加。调用所有相同事件的顺序,例如Awake
或Start
未确定,可能会更改。但任何Awake
总是在任何Start
之前调用。因此,如果您想在Start
中执行事件,则必须在Awake
中添加侦听器。
此外,正如程序员在评论中所说,并不总是调用Start
。如果在场景开始播放时禁用GameObject,则在启用对象之前不会调用Start
,但始终会调用Awake
。
此外,正如PMV在他的评论中所说,在继承的类中使用Start
将阻止在基类中调用Start
。在这种情况下,您应该收到有关隐藏继承方法的方法的警告。如果你没有收到警告,问题不在这里。顺便说一下,如果需要添加一些功能,最好在基类中将Start
和Awake
等方法标记为virtual
,并在继承类中覆盖它。