简体   繁体   中英

Unity: Why Adding an Event Listener work only in Awake function?

I'd like to understand more about the following scenario. I have a simple base class that has a public variable of type Button. In my Start function, I use the Button's click event and add a listener to it. However, the code simply does not execute, and the only way it works is if the event listener is hooked in an Awake function as opposed to a Start function.

Event does NOT execute in the following:

 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);
    }

Event executes and works as intended. Note the only thing that changed was 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);
    }

I am aware that the Awake function is called before the Start function. But I don't see how that affects the process - in fact, I would assume the Start methods should work better as I can be sure the Button is properly initialized or instantiated alongside this script.

Additional Note: The above script is the base of the UI manager class I am using for a UI GameObject that houses a set of panels and UI elements. One of the child panels include the Exit button referenced above.

In my Start function, I use the Button's click event and add a listener to it.

It is a key to your problem.

If you want to execute the listener's code, you will need to add the listener before executing the event. Otherwise delegate can't execute it, because it don't know anything about what it must execute.

When you add a listener and execute in Start() , you can't guarantee the adding will called first. Order of calling all same events like Awake , or Start not determined, and may change. But any Awake always call before any Start . So if you want execute event in Start , you must add listener in Awake .

Also, as Programmer said in a comment, Start is not always called. If the GameObject is disabled when the scene begins playing, Start will not be called until the object is enabled, but Awake will always be called.

Also, as PMV said in his comment, using Start in inherited class will prevent Start from being called in the base class. In this case you should get a warning about your method hiding an inherited method. If you did not get that warning, the problem is not here. Btw it's better to mark methods like Start and Awake as virtual in base class, and override it in inherited class, if you need to add some functionality.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM