Receive touch event on brother nodes

I have the following hierarchy structure:

Container
|-> A
|-> B
|-> C
|-> …
|-> Z

Where every child node is a Sprite. I want to be able to drag any of them and in case two sprites are overlapping both of them should be dragged at the same time. But it seems I cannot capture the same touch event on two nodes that are not child-parent related (or in a direct hierarchy line). How can I do this?

Thanks.

Hi @Nicolas-Ezcurra , welcome to our forum :smiley:

I think we cannot get the same event on the brothers because the event bubble flows to the parent.
What I would do is identify the touch position and then check if its on the childrens, select those childrens and move them.

I’ve made a code here to help you get started

const {ccclass, property} = cc._decorator;

@ccclass
export default class NewClass extends cc.Component {

childs: cc.Node[] = [];
selectedNodes: cc.Node[] = [];

onLoad () {
    this.childs = this.node.children;
}

start () {
    this.childs.forEach(child => {
        child.on(cc.Node.EventType.TOUCH_START, this.onTouchStart.bind(this));
        child.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove.bind(this));
    });
}

onTouchStart(touchEvent) {
    this.selectedNodes = [];
    const touchPosition = touchEvent.currentTouch.getLocation();
    this.selectedNodes = this.getSelectedNodes(touchPosition);
    cc.log(this.selectedNodes);
}

getSelectedNodes(touchLocation) : Array<cc.Node>{
    const selected = [];
    for (const node of this.childs) {
        let nodeSpace = this.node.convertToNodeSpaceAR(touchLocation);
        if(node.getBoundingBox().contains(nodeSpace)){
            selected.push(node);
        }
    }
    return selected;
}

onTouchMove(touchEvent) {
    const touchDelta: cc.Vec3 = touchEvent.currentTouch.getDelta();
    if(this.selectedNodes.length == 0) {return;}
    this.selectedNodes.forEach(childNode => {
        childNode.setPosition(childNode.position.add(touchDelta));
    });
}}

Here the parent will wait some child be touched, then verify if the touch is on the boundingBox of any other child, select them and move them together.

image

cocos_move_together

1 Like

Thank you very much! Seems like the best solution indeed.

Nevertheless I would love to have the option to allow events pass through the top receiving node with for example a return flag on the callback function. Something like this:

onTouchStart(touchEvent) {

return false; // This for allowing the events not being consumed would be awesome
}

But given the current limitations, your solution as I said before is the way to go.

I’m testing here…
I can also get the touch events from the parent node if I listen ( this.node.on ), and get the touched node from the touch event. ( event.target )

But again, seems we are not going to receive from all the childrens, just from the sprite on the top

start () {
this.node.on(cc.Node.EventType.TOUCH_START, (event:cc.Event.EventTouch) => {
    console.log("parent touch start");
    console.log(`child with ${event.target.name} was touched!`);
});

this.childs.forEach(child => {
    child.on(cc.Node.EventType.TOUCH_START, () => {});
    child.on(cc.Node.EventType.TOUCH_MOVE, () => {});
}); }

But if I dont register the .on on the children, the parent will not be called either.
so seems we need to put at least a empty callback there.

if you are handling the touch on the children and don’t want the parent to receive, you can call stopPropagation on the event

onTouchStart(touchEvent) {
touchEvent.stopPropagation();}
1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.