cocos 3.8.2 诡异的emit消息BUG,整了一天,什么方法都试了

cocos 3.8.2 诡异的emit消息BUG,整了一天,什么方法都试了,请教高手给个办法

  • Creator 版本: cocos 3.8.2

  • 目标平台: chrome ,firefox反正都是一样的结果

  • 重现方式:
    两段代码放在两个文件中绑在两个父子节点上,
    节点关系》
    Node
    L tester

Node节点用脚本:parentNode.ts
tester节点用脚本:childNode.ts

========= parentNode.ts ===========
import { _decorator, Component, Node,EventTarget } from ‘cc’;
const { ccclass, property } = _decorator;

@ccclass(‘parentNode’)
export class parentNode extends Component {
onLoad() {
}

start() {
  this.node.on('aaa', this.onCustomEvent);  
  console.log("onstart");  
}

update(deltaTime: number) {

}


// 定义事件处理函数  
onCustomEvent(event) {  
    // 处理事件,event.detail 中包含了子节点传递的数据  
    console.log("oncustomevent():"+JSON.stringify(event));  
    console.log("oncustomevent():"+event.ok);  

}

}

========= childNode.ts =============
import { _decorator, Component, Node,EventTarget} from ‘cc’;
const { ccclass, property } = _decorator;

@ccclass(‘childNode’)
export class childNode extends Component {

start() {
  this.node.on('aa', this.onCustomEvent2);  

  this.node.emit('aa', { "ok":"ok4"});

  this.node.emit('aaa', { "ok":"ok5"});

  console.log("child onstart");  
}

update(deltaTime: number) {
}

onCustomEvent2(event) {  
    // 处理事件,event.detail 中包含了子节点传递的数据  
    console.log("oncustomevent():"+JSON.stringify(event));  
    console.log("oncustomevent():"+event.ok);  

}

}

代码说明:
在父节点中加入监听器,监听“aaa"消息
在子节点中加入监听器,监听“aa"消息
然后在子节点中发送2个消息 “aa”,“aaa”

结果:
onload [parentNode.ts:11:14]
onstart [parentNode.ts:21:14]
oncustomevent():{“ok”:“ok4”} [childNode.ts:31:16]
oncustomevent():ok4 [childNode.ts:32:16]
child onstart

说明:
只有子节点中的消息能被子节点中的监听器捕获,输出打印内容
而父节点无法捕获到子节点发出的消息。不管怎么变换写法,也收不到!

  • 编辑器操作系统: VSCode
  • 重现概率: 100000%

没有跑你逻辑,但是听你转述看了下代码,感觉此处会有问题。尝试一下呗
方式一、注册的地方改成: this.node.on(‘aaa’, this.onCustomEvent,this) ;
方式二、this.node.on(‘aaa’, this.onCustomEvent)不指定this对象,但是把 onCustomEvent 这个函数修改为箭头函数

感谢回复
方式一已试过了,不可以的,没用
方式二倒是很清奇,感觉可能有奇效,我试一下先

this.node.on(‘aaa’, (event)=>
{
console.log(“aaa”)
console.log(“oncustomevent():”+JSON.stringify(event));
console.log(“oncustomevent():”+event.ok);
});

方式二试了,一样没有效果
onload [parentNode.ts:11:14]
onstart [parentNode.ts:21:14]
oncustomevent():{“ok”:“ok4”} [childNode.ts:31:16]
oncustomevent():ok4 [childNode.ts:32:16]
child onstart

哦,这样的嘛。我跑一下你逻辑,验证一下。稍等。出问题一定是代码的问题。按道理这种级别的bug,应该不是引擎的底层导致的。

实验出来了,3.x 在这边不知道哪个版本之后修改了自定义事件发送接受的方式
1713025128000
image
image
image
需要使用new EventTarget() 实例出来的对象进行自定义事件的注册分发了
注意:要使用同一个对象!!!(这里刚才卡了我一会儿),需要export const eventTarget = new EventTarget(),相对应使用 eventTarget.emit 类中引入一下这个对象

文档还是挺重要的,我也基本上都是使用2.x版本开发。毕竟我们作为个体,很多时候挺容易出现细节上粗心或者知识上欠缺等影响导致判断失误。遇到问题先怀疑自己,然后对照使用的api规则、检查我们的代码,然后论坛上应该也有其他人遇到这种和之前相同功能但是api使用方式修改的情况。一起加油 :zzz: :fist_left:

改的妙啊,传统不能丢,,

好的,马上验证,并给出结果

验证通过,如果使用this.node.on方式还是没有结果,不知怎么样才能让他可以在早前的版本中

破案了,使用这种方式可以完美运行,但仍然留下了一个未解之谜那就是使用this.node.on()这种方式还没有通过,以下是参考代码使用的是 eventtarget方式
========= parentNode.ts ===========
import { _decorator, Component, Node,EventTarget } from ‘cc’;
const { ccclass, property } = _decorator;
export const eventTarget =new EventTarget();
@ccclass(‘parentNode’)
export class parentNode extends Component {
start() {
eventTarget.on(‘aaa’, this.onCustomEvent, this);
console.log(“onstart”);
}

update(deltaTime: number) {

}


// 定义事件处理函数  
onCustomEvent(event) {  
    console.log("oncustomevent() aaa:"+JSON.stringify(event));  
    console.log("oncustomevent() aaa:"+event.ok);  

}

}

========= childNode.ts =============
import { _decorator, Component, Node,EventTarget} from ‘cc’;
import {eventTarget} from ‘./parentNode’;
const { ccclass, property } = _decorator;
@ccclass(‘childNode’)

export class childNode extends Component {
start() {
eventTarget.on(‘aa’, this.onCustomEvent2, this);
eventTarget.emit(‘aa’, { “ok”:“ok4”});
eventTarget.emit(‘aaa’, { “ok”:“ok5”});
console.log(“child onstart”);
}

update(deltaTime: number) {
}
onCustomEvent2(event) {  
    console.log("oncustomevent2 aa():"+JSON.stringify(event));  
    console.log("oncustomevent2 aa():"+event.ok);  
}

}


结果:
onstart
childNode.ts:25 oncustomevent2 aa():{“ok”:“ok4”}
childNode.ts:26 oncustomevent2 aa():ok4
parentNode.ts:27 oncustomevent() aaa:{“ok”:“ok5”}
parentNode.ts:28 oncustomevent() aaa:ok5
childNode.ts:17 child onstart
完全正确达到预期

那么有谁知道使用这种方式来实现的请回复,谢谢,
this.node.on()

emit事件不会向上冒泡,父节点收不到。要用dispatchEvent

4赞

3.x是不建议在node上监听自定义事件的, 每个node都有一个自己的NodeEventProcessor,Node.on Node.emit 都是这个对象在处理的,你要跨节点发消息就得找到这个节点的NodeEventProcessor, 虽然可以用Node.dispatchEvent(new Event(“name”, isBubble)) 的是否冒泡参数为true来自动查找父节点的NodeEventProcessor, 但是最多只能子节点发消息给父节点,父节点发消息给子节点就不行了,而且这样效率也很低。
我们的做法是封装一个类比如叫AppNotification, 是一个单例 继承EventTarget, 所有系统级的自定义事件就又它来处理。
如果嫌麻烦实际上还可以在game 或者director这些对象上注册和发射事件,这两个对象也都是单例 继承了EventTarget,不过这种方式一定要在节点或者组件destroy的时候off掉

1赞

感谢回复,
可是剧我所知,3。8。2版本中没有对dispatchEvent方法,能否给出用例,谢谢

感谢回复,
能否给出用例,NodeEventProcessor,谢谢,我相信以后很多人看到我们的答案回感谢我们的,

是不是要先生成一个eventProcessor对象再调用它的dispatchEvent()方法?

在onLoad里面监听试一下

那个NodeEventProcessor是Node的属性,按道理应该不用它, 这是封装一个AppNotification的例子

import { EventTarget } from "cc";

export class AppNotification extends EventTarget {
    private constructor() {
        super();
    }

    private static instance: AppNotification;
    public static getInstance() {
        if (!this.instance) {
            this.instance = new AppNotification();
        }

        return this.instance;
    }

    public static on(eventName: string, cb: (arg: any)=>void, target: any) {
        this.getInstance().on(eventName, cb, target);
    }

    public static off(eventName: string) {
        this.getInstance().off(eventName);
    }

    public static targetOff(target: any) {
        this.getInstance().targetOff(target);
    }


    public static emit(eventName: string, arg: any) {
        this.getInstance().emit(eventName, arg);
    }
}

用法

@ccclass('Child')
export class Child extends Component {
    protected onLoad(): void {
        AppNotification.on("MyEvent1", (arg)=>{
            console.log("child收到MyEvent1事件:" + arg);
        }, this);
    }

    start() {
        AppNotification.emit("MyEvent1", "子节点发送")
    }

    protected onDestroy(): void {
        AppNotification.targetOff(this);
    }
}

@ccclass('Parent')
export class Parent extends Component {
    protected onLoad(): void {
        AppNotification.on("MyEvent1", (arg)=>{
            console.log("parent收到MyEvent1事件:" + arg);
        }, this);
    }

    start() {
        AppNotification.emit("MyEvent1", "父节点发送")
    }

    protected onDestroy(): void {
        AppNotification.targetOff(this);
    }
}