Unity3D自定义UnityEvent添加监听后无法触发问题求助
问题排查与修复方案
嘿,我一眼就揪出了问题的关键——你在Rotator的Start()里手动重新实例化了OnRotate事件,这直接把Owner添加的监听给“冲没”了!
问题出在哪?
当你在脚本里声明public UnityEvent OnRotate;时,Unity会自动帮你初始化这个事件实例(除非你手动在Inspector里清空它)。你的Owner脚本在Start()阶段给这个实例挂上了监听,但随后Rotator的Start()执行了OnRotate = new UnityEvent();——这相当于把原来带着监听的事件对象丢了,换成了一个全新的空事件。所以后来调用OnRotate.Invoke()时,触发的是这个空的新实例,自然不会有任何监听响应。
你可以自己验证:在Rotator的Start()里加一行print(OnRotate.GetInstanceID()),会发现它和Owner里打印的事件实例ID完全不一样!
怎么修复?
最简单的办法就是删掉Rotator的Start()里那行OnRotate = new UnityEvent();,Unity已经帮你初始化好了,不需要画蛇添足。
修改后的Rotator代码:
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.eulerAngles.z; // 顺便提一句,你这里拼写错了,是eulerAngles不是eulersAngles if (newAngle != angle) { print ("Actual Instance ID: " + GetInstanceID()); print ("Invoking!"); OnRotate.Invoke(); angle = newAngle; } } }
另外注意你代码里的小拼写错误:transform.rotation.eulersAngles应该是eulerAngles,虽然这不影响监听失效,但修正后能避免后续的逻辑错误。
额外的优化建议
- 如果你想确保事件实例不会为null,但又不想覆盖已有的监听,可以改用懒加载的方式在
Awake()里初始化:
void Awake() { if (OnRotate == null) { OnRotate = new UnityEvent(); } }
这样只有当事件实例真的为空时才会创建,不会破坏已经添加的监听。
- 从封装性考虑,你可以把事件设为私有,用
[SerializeField]让它在Inspector里可见,再通过只读属性暴露出去,避免外部意外修改:
[SerializeField] private UnityEvent _onRotate; public UnityEvent OnRotate => _onRotate;
内容的提问来源于stack exchange,提问作者Justin Lloyd
相关产品推荐
相关产品推荐

