You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,虽然这不影响监听失效,但修正后能避免后续的逻辑错误。

额外的优化建议

  1. 如果你想确保事件实例不会为null,但又不想覆盖已有的监听,可以改用懒加载的方式在Awake()里初始化:
void Awake() {
    if (OnRotate == null) {
        OnRotate = new UnityEvent();
    }
}

这样只有当事件实例真的为空时才会创建,不会破坏已经添加的监听。

  1. 从封装性考虑,你可以把事件设为私有,用[SerializeField]让它在Inspector里可见,再通过只读属性暴露出去,避免外部意外修改:
[SerializeField]
private UnityEvent _onRotate;
public UnityEvent OnRotate => _onRotate;

内容的提问来源于stack exchange,提问作者Justin Lloyd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:10:25