Unity3D:自定义UnityEvent AddListener不触发

时间:2019-10-09 14:44:17

标签: unity3d

我有自己的自定义UnityEvent,正在尝试添加侦听器。
我在许多其他UI对象(例如按钮,下拉菜单,切换按钮等)上使用了AddListener,因此我理解了这一过程。但是,当我Invoke我的UnityEvent时,它根本不会触发。 我没有收到任何错误消息,并且在阅读和研究之后,一切看起来都正确。因此,不确定下一步该怎么做。

这是一个旋转时发出的对象。

这是我代码的基础:

using UnityEngine.Events;

public class Rotator: MonoBehaviour 
{
    public UnityEvent OnRotate;
    int angle = 0;
    int newAngle = 0;

    void Start() 
    {
        OnRotate = new UnityEvent();
    }

    void Update() 
    {
        newAngle = (int)transform.rotation.eulersAngles.z;

        if (newAngle != angle) 
        {
            print ("Actual Instance ID: " + GetInstanceID());
            print ("Invoking!");
            OnRotate.Invoke();
            angle = newAngle;
        }
    }
}

public class Owner: MonoBehaviour 
{
    public Rotator rotator;

    void Start() 
    {
        print ("Rotator Instance ID: " + rotator.GetInstanceID());
        rotator.OnRotate.AddListener(
            () => UpdateRotation()
        );
    }

    void UpdateRotation() 
    {
        print ("Invoked!");
    }
}

Rotator的角度改变时,我在控制台中得到了它:

Actual Instance ID: 11234
Rotator Instance ID: 11234
Invoking!

实例ID是为了确保我正在使用相同的对象并且不会无所事事。它们匹配,所以我在听正在发射的物体。 但是,听众不会开火。我已经尝试了与委托等的不同组合,但是都是一样的。没有错误。它只是不调用。

很明显,我做错了什么,但这是什么?

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

您可以使用之前在First Version of your Question中提供的代码来完全回答问题的新编辑版本!

正如我试图告诉您的那样……如果您在代码中的任何位置都进行OnRotate = new UnityEvent(),那么您当然会擦除此刻之前的所有持久性回调和所有运行时回调!


简而言之

只需将其保留为

public UnityEvent OnRotate;

,您甚至不必再考虑它。


要了解为什么将其放在Awake中也能起作用,请简单查看Order of Execution for Event Functions

→每个游戏对象/组件首先调用AwakeOnEnabled。然后,一旦GameObject / Component处于活动状态,就会调用所有Start方法。

在每个块(AwakeOnEnable和(Start中,除非您通过{{3 }},您可以定义Owner只是在Rotator之前运行。然后将两者都包含在Start中也将再次起作用。


如果您在public字段上执行此操作,为什么它也起作用?

→因为此字段是序列化的。这意味着它会在Inspector中自动初始化,然后与Scene或预制资产(包括任何持久回调)一起存储。

然后,后来Unity重新使用字段的序列化版本,因此实际上您可以完全删除new UnityEvent();,因为它对序列化字段没有任何影响!无论如何,它总是会自动初始化!

答案 1 :(得分:0)

好的,我发现了问题所在。 我的问题现在是“为什么?”。

我更改了以下代码:


public UnityEvent OnRotate;

void Start() {
  OnRotate = new UnityEvent();
}

public UnityEvent OnRotate = new UnityEvent();

void Start() {
}

现在可以使用了。

尽管,现在我考虑了一下,Awake()是它们都在初始化之前启动的方法,而Start()是创建对象时的方法。因此,Start()中的Rotator可能在<{>}添加Owner之后被称为