Unity:为啥添加事件侦听器仅在唤醒功能中起作用?
Posted
技术标签:
【中文标题】Unity:为啥添加事件侦听器仅在唤醒功能中起作用?【英文标题】:Unity: Why Adding an Event Listener work only in Awake function?Unity:为什么添加事件侦听器仅在唤醒功能中起作用? 【发布时间】:2017-10-19 01:38:51 【问题描述】:我想了解更多关于以下场景的信息。我有一个简单的基类,它有一个 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);
我知道 Awake 函数是在 Start 函数之前调用的。但我看不出这对流程有何影响 - 事实上,我认为 Start 方法应该会更好地工作,因为我可以确定 Button 已正确初始化或与此脚本一起实例化。
附加说明:上面的脚本是我用于 UI 游戏对象的 UI 管理器类的基础,它包含一组面板和 UI 元素。其中一个子面板包括上面提到的退出按钮。
【问题讨论】:
我怀疑Start
函数甚至没有被调用。使用Debug.Log
来验证这一点。
你的派生类是否也实现了 Start()?如果是这样,您也有责任调用基类的 Start() 方法。 Unity 只会调用最派生的 Start() 实现。此外,您可能会考虑根本不使用继承,而是使用组合(使您的共享代码成为自己的脚本组件)。
【参考方案1】:
在我的 Start 函数中,我使用了 Button 的点击事件并为其添加了一个监听器。
这是解决您问题的关键。
如果你想执行监听器的代码,你需要在执行事件之前添加监听器。否则委托不能执行它,因为它不知道它必须执行什么。
当你添加一个监听器并在Start()
中执行时,你不能保证添加会首先被调用。调用所有相同事件(如 Awake
或 Start
)的顺序未确定,并且可能会更改。但是任何Awake
总是在任何Start
之前调用。所以如果你想在Start
中执行事件,你必须在Awake
中添加监听器。
另外,正如程序员在评论中所说,Start
并不总是被调用。如果在场景开始播放时禁用 GameObject,则在启用该对象之前不会调用 Start
,但始终会调用 Awake
。
另外,正如 PMV 在他的评论中所说,在继承类中使用 Start
将阻止在基类中调用 Start
。在这种情况下,您应该收到有关您的方法隐藏继承方法的警告。如果您没有收到该警告,则问题不在这里。顺便说一句,如果需要添加一些功能,最好在基类中将Start
和Awake
等方法标记为virtual
,并在继承类中覆盖它。
【讨论】:
他的Start()
和 Awake()
方法被标记为 private 这将它们从 IDE 中排除了有关隐藏基类方法的警告,但由于 Unity 使用反射巫术来调用这些方法,基类方法仍然被隐藏。我总是将我的 Unity 关键字方法标记为 public
,因为我知道它们将被外部调用并避免此问题。
@Draco18s protected
而不是 public
使您的对象对其他类具有更清晰的 API 服务,并且您仍然可以获得派生类能够看到它的好处。
@ScottChamberlain 确实如此。
知道了!也非常感谢其他提示,尤其是我忽略了继承类中的 Start 方法交互这一事实。以上是关于Unity:为啥添加事件侦听器仅在唤醒功能中起作用?的主要内容,如果未能解决你的问题,请参考以下文章