More than 1 node listening custom events?

Hi is it possible to have more than 1 node listening to the same custom event?

Edit: solved!!!
I guess I got something wrong in dispatchevent but honestly I dont know what it was. Now it works.
This is how I did it:

I have 3 nodes listening the event:

this.node.on(GEVENT.ACTION_COMPLETED,this._callback);

And then, at some point I fire the event:

this.node.dispatchEvent(new cc.Event.EventCustom(GEVENT.ACTION_COMPLETED, true));

And all 3 nodes got the notification.

1 Like

Thanks for sharing the info. This is exatcly what I need! :slight_smile:

There is a big ā€œbutā€. I believe I found a bug.

If the 3 nodes have the same script (for example, it is used in a prefab and you instantiate 3 objects), does not work, and only one of the objects got the notification.

Im building a test project to test all cases but this is very frustrating… I don’t want to have 3 different scripts doing the same and actually I cant do that because I have an unknown number of objects in my game. I need all of them to listen the event… and it doesn’t work. It would be great if the dev team can confirm this as a bug.

Maybe there is some misunderstanding about the event mechanism in Creator.

All node is mixin-ed with EventTarget, so you can listen to the events it dispatch. So it’s a straight forward target-observer relationship, and it’s one to one.

If you on a listener to a node A, the node A is the listener’s target, only if the node A dispatch or emit the event, your listener can receive it. If node B emit the same event, your listener won’t respond.

I’m not very sure, but are you looking for one to all event dispatching ? If so, it’s also very easy:

var oneToAllTarget = new cc.EventTarget();
oneToAllTarget.on('eventName', listener1);
oneToAllTarget.on('eventName', listener2);
oneToAllTarget.on('eventName', listener3);

oneToAllTarget.emit('eventName'); // All three listener get notified

So be aware which target you are adding your listener, and don’t mix them up

1 Like

Hi @pandamicro, thank you for your response. I’ve tried with emit but it only works if the event target is the same as the emiter. I do have this node system:

Canvas->[A,B,C,D,E,…]

A,B,C,D, etc… are sister nodes with the same script. Each one of the has this:

this.node.on('done',this._callback);

and when somebody touch the node (is a sprite) fires the event:

this.node.emit('done');

So, if node A fires the event (this.node.emit('done');) only node A gets the notification. And I want all the sisters node got them, thats why I tried with dispatchEvent.

Edit: Found a solution

I have built this system to test it:

Container node (CN) is an empty node that acts as a container. It has the script registerEvents.js:

cc.Class({
    extends: cc.Component,

    properties: {
    },

    // use this for initialization
    onLoad: function () {

    },

    subscribeEvent: function(event,_callback,self)
    {
        this.node.on(event,_callback,self);
        cc.log("event registered");
    },
    
    sendEvent: function(event)
    {
        this.node.emit(event);
        //this.node.dispatchEvent(new cc.Event.EventCustom('done', true));
    }
});

Trigger is the smallest sprite. Acts as event trigger when touched. It has the script sendEvent.js:

cc.Class({
    extends: cc.Component,

    properties: {

    },

    onLoad: function () {
        this.node.on(cc.Node.EventType.TOUCH_START, this.Touched, this);
    },

    Touched: function () {
        cc.log("Fire event done");
        //this.node.dispatchEvent(new cc.Event.EventCustom('done', true));
        var sender = this.node.parent.getComponent('registerEvents');
        sender.sendEvent('done');
    },
});

And finally, I do have 3 sister nodes that have the same script: observer.js

cc.Class({
    extends: cc.Component,

    properties: {

    },

    // use this for initialization
    onLoad: function () {
        //this.node.on('done',this._callback);
        var reg = this.node.parent.getComponent('registerEvents');
        reg.subscribeEvent('done',this._callback,this)
    },
    
    _callback: function()
    {
        cc.log("event received at Observer point.");
    }
});

So, the A,B,C nodes register their listeners at CN node. And trigger script, calls a function at CN node that fires the event (emit). So all 3 events are listening at the same node that emits the event. The trick is to use a single script to register and fire the events, no matter where the real emitter and the observers are.

The emitter can be one of the A-B-C nodes too. This does the trick for me.

@pandamicro is there a better way to do it?

That’s exactly what I meant, the emitter can only emit / dispatch events to its own listeners, listeners can only respond to the registered target. It’s designed this way.

You actually want a centralized dispatcher, the solution you provided was to create a delegator as the dispatcher which receive all events manually and then dispatch events via itself. It’s ok to do so.

Need to clarify that dispatchEvent can dispatch events to the target’s parent, if the parent listen to the same event. So you don’t need to redistribute the TOUCH_START, you can just listen to ā€˜TOUCH_START’ in the target node’s parent, the parent can receive the event if it’s triggered in its children (and if the children haven’t stopped propagation). So here is a solution to your problem:

CN need to listen to ā€˜TOUCH_START’ event

nodeCN.on(cc.Node.EventType.TOUCH_START, function (event) {
    // Simple way to detect real target, if the target isn't itself, it means the event is propagated from its children A, B, or C. You can also check whether the target is one of the three which is more strict
    if (event.target != this) {
        this.emit(new cc.Event.EventCustom('done', true));
    }
}, nodeCN);

A, B, C need to listen the done event of CN, I reuse your observer.js

cc.Class({
    extends: cc.Component,

    properties: {

    },

    // use this for initialization
    onLoad: function () {
        var nodeCN = this.node.parent;
        nodeCN.on('done', this._callback, this);
    },
    
    _callback: function()
    {
        cc.log("event received at Observer point.");
    }
});

Ok, I understand. Thanks for the feedback!

Just to add a point to this topic. I’ve followed the manual at http://cocos2d-x.org/docs/editors_and_tools/creator-chapters/scripting/events/ and there is an error in there

If I do that:

this.node.dispatchEvent(new cc.Event('myevent', true));

It is going to work in browser, but not when running in Android.

You need to do that:

this.node.dispatchEvent(new cc.Event.EventCustom('myevent', true));
1 Like

This approach is a observer design pattern…

here is a good link…

Hi,this is exactly what I did, implementing an Observer pattern. Thanks for the video!