我有自己的自定义 UnityEvent,并尝试添加一个侦听器。
我已经使用过AddListener许多其他 UI 对象,例如按钮、下拉菜单、切换开关等,所以我了解这个过程。但是,当我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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
和
public class Owner: MonoBehaviour
{
public Rotator rotator;
void Start()
{
print ("Rotator Instance ID: " + rotator.GetInstanceID());
rotator.OnRotate.AddListener(
() => UpdateRotation()
);
}
void UpdateRotation()
{
print ("Invoked!");
}
}
Run Code Online (Sandbox Code Playgroud)
当Rotator角度改变时,我在控制台中得到:
Actual Instance ID: 11234
Rotator Instance ID: 11234
Invoking!
Run Code Online (Sandbox Code Playgroud)
实例 ID 是为了确保我正在使用相同的对象,而不是毫无意义地兜圈子。它们匹配,所以我正在聆听正在发射的物体的声音。然而,听众并没有开火。我尝试过与代表等的不同组合,但都是一样的。没有错误。它只是不调用。
显然,我做错了什么,但这是什么?
谢谢你的帮助。
不知何故,您用您之前在问题的第一个版本中提供的代码完全回答了问题的新编辑版本!
正如我试图告诉你的那样......如果你在代码中的任何地方这样做,OnRotate = new UnityEvent()当然你会删除任何持久回调和在那一刻之前添加的任何运行时回调!
简而言之
只需将其保留为
public UnityEvent OnRotate;
Run Code Online (Sandbox Code Playgroud)
你甚至不必再考虑它了。
要理解为什么它也可以工作,如果你把它放进去,Awake请简单地看一下事件函数的执行顺序
→ 首先Awake,OnEnabled为每个游戏对象/组件调用。Start一旦游戏对象/组件处于活动状态,所有方法都会被调用。
在每个块 ( Awake+ OnEnable) 和 ( Start) 中,不保证不同组件类型之间的执行顺序,除非您通过脚本执行顺序设置显式配置它,您可以在其中定义Owner简单地在Rotator.. 之前运行,然后将两者都包含在内Start也会再次工作。
为什么在现场做也能发挥作用public?
→ 因为这个字段是序列化的。这意味着它会在检查器中自动初始化,然后与场景或预制资源(包括任何持久回调)一起存储。
然后,稍后 Unity 会重新使用该字段的序列化版本,因此实际上您可以完全删除它,new UnityEvent();因为它对序列化字段没有任何影响!无论如何它总是会自动初始化!