Unity:为什么添加事件监听器只能在Awake功能中工作?

时间:2017-10-19 01:38:52

标签: c# events unity3d onclicklistener

我想更多地了解以下情况。我有一个简单的基类,它有一个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元素。其中一个子面板包括上面引用的“退出”按钮。

1 个答案:

答案 0 :(得分:2)

  

在我的Start函数中,我使用Button的click事件并为其添加一个监听器。

这是解决问题的关键。

如果要执行侦听器的代码,则需要在执行事件之前添加侦听器。否则委托不能执行它,因为它不知道它必须执行什么。

当您添加侦听器并在Start()中执行时,您无法保证首先调用添加。调用所有相同事件的顺序,例如AwakeStart未确定,可能会更改。但任何Awake总是在任何Start之前调用。因此,如果您想在Start中执行事件,则必须在Awake中添加侦听器。

此外,正如程序员在评论中所说,并不总是调用Start。如果在场景开始播放时禁用GameObject,则在启用对象之前不会调用Start,但始终会调用Awake

此外,正如PMV在他的评论中所说,在继承的类中使用Start将阻止在基类中调用Start。在这种情况下,您应该收到有关隐藏继承方法的方法的警告。如果你没有收到警告,问题不在这里。顺便说一下,如果需要添加一些功能,最好在基类中将StartAwake等方法标记为virtual,并在继承类中覆盖它。