Touch propogation; touch swallow

Hi,

need help with touch swallowing. I’ve been adding new layers to existing layers and the touches seep through from the top most layer to the layers beneath it.

Tried many methods using touch dispatcher, touch priority, zIndex and all but to no avail. Can someone advise on the proper way to swallow touch from one layer to another? All these layers are within a scene.

I’ve already built the core bits of a module and am in need of an answer~

Hi,

I made a sample scene for testing the touch events, and this include a swallow layer, so try it out to see if it can helps you resolve your problem.
It’s true that the current event dispatcher is sometimes tricky and not very easy to use. Don’t worry, the main improvement in the next release will be the new event dispatcher. It will be totally recoded, and you may set listeners for every node, not just the layers.

Huabin

var Rect = cc.DrawNode.extend({
    corners: null,
    ctor: function(rect, color) {
        this._super();
        this.init();

        this.corners = [cc.p(0, 0),
                        cc.p(0, rect.height),
                        cc.p(rect.width, rect.height),
                        cc.p(rect.width, 0)];
        this.drawPoly(this.corners, color, 0, color);
        this.setAnchorPoint(0, 0);
        this.setPosition(rect._origin);
        this.setContentSize(rect._size);
    },

    changeColor: function(color) {
        this.clear();
        this.drawPoly(this.corners, color, 0, color);
    }
});

var TestLayer = cc.Layer.extend({
    name: null,
    nameLabel: null,
    target: null,
    activeColor: cc.c4f(1, 0, 0, 1),
    color: null,
    touching: false,

    ctor: function(name, priority) {
        this._super();
        this.name = name || "";
        this.nameLabel = cc.LabelTTF.create(this.name, "Helvetica", 13, cc.size(260, 30), cc.TEXT_ALIGNMENT_RIGHT);
        this.nameLabel.setAnchorPoint(1, 1);

        this.setTouchEnabled(true);
        this.setTouchPriority(priority);
    },

    setTouchTarget: function(rect, color) {
        this.color = color;
        this.target = new Rect(rect, color);
        this.addChild(this.target);

        this.nameLabel.setPosition(cc.p(rect.x+rect.width, rect.y+rect.height));
        this.addChild(this.nameLabel);
    },

    testTouch: function(touch) {
        var tpos = touch.getLocation(), tx = tpos.x, ty = tpos.y,
            origin = this.target.getPosition(), ox = origin.x, oy = origin.y,
            size = this.target.getContentSize(), w = size.width, h = size.height;
        if(tx > ox && tx < ox+w && ty > oy && ty < oy+h)
            return true;
        else return false;
    },

    onTouchesBegan: function(touches) {
        if(this.testTouch(touches[0])) {
            this.touching = true;
            this.target && this.target.changeColor(this.activeColor);
            (logTest || cc.log)(this.name + ": Touch began");
        }
    },

    onTouchesMoved: function(touches) {

    },

    onTouchesEnded: function() {
        if(this.touching) {
            this.target && this.target.changeColor(this.color);
            (logTest || cc.log)(this.name + ": Touch ended");
            this.touching = false;
        }
    },

    onTouchBegan: function(touch) {
        if(this.testTouch(touch)) {
            this.target && this.target.changeColor(this.activeColor);
            (logTest || cc.log)(this.name + ": Touch began");
            return true;
        }
        else return false;
    },

    onTouchMoved: function(touch) {

    },

    onTouchEnded: function(touch) {
        if(this.testTouch(touch)) {
            this.target && this.target.changeColor(this.color);
            (logTest || cc.log)(this.name + ": Touch ended");
            return true;
        }
        else return false;
    }
});

var SwallowLayer = TestLayer.extend({
    ctor: function(name, priority) {
        this._super(name, priority);
        this.setTouchMode(cc.TOUCH_ONE_BY_ONE);
    }
});

var PropaLayer = TestLayer.extend({
    ctor: function(name, priority) {
        this._super(name, priority);
        this.setTouchMode(cc.TOUCH_ONE_BY_ONE);
        this._isTouchEnabled = true;
        cc.registerTargetedDelegate(this._touchPriority, false, this);
    }
});


var TouchPropagationTest = cc.Scene.extend({
    ctor: function() {
        this._super();

        var winSize = cc.Director.getInstance().getWinSize(), w = winSize.width, h = winSize.height;

        var propaLayer1 = new PropaLayer("Propagation Layer Priority 5", 5);
        propaLayer1.setTouchTarget(cc.rect(0, 0, w, h), cc.c4f(0.97, 0.76, 0.8, 1));

        var standardLayer1 = new TestLayer("Standard Layer Priority 4", 4);
        standardLayer1.setTouchTarget(cc.rect(0, 0, w*0.8, h*0.8), cc.c4f(0.96, 0.36, 0.18, 1));

        var swallowLayer = new SwallowLayer("Swallow Layer Priority 3", 3);
        swallowLayer.setTouchTarget(cc.rect(w*0.1, h*0.1, w*0.6, h*0.6), cc.c4f(0.45, 0.29, 0.22, 1));

        var propaLayer2 = new PropaLayer("Propagation Layer Priority 2", 2);
        propaLayer2.setTouchTarget(cc.rect(0, 0, w*0.4, h*0.4), cc.c4f(0.74, 0.76, 0.25, 1));

        var standardLayer2 = new TestLayer("Standard Layer Priority 1", 1);
        standardLayer2.setTouchTarget(cc.rect(0, 0, w*0.2, h*0.2), cc.c4f(0.4, 0.73, 0.7, 1));

        this.addChild(propaLayer1);
        this.addChild(standardLayer1);
        this.addChild(swallowLayer);
        this.addChild(propaLayer2);
        this.addChild(standardLayer2);
    }
});

TouchPropagationTest.create = function() {
    return new TouchPropagationTest();
}

Thanks a lot!

I’ve successfully integrated your approach into my code and it works fine :smiley:

I have to say, however:

  1. (logTest || cc.log) kept giving me undefined error in the console (firefox 26)
  2. what this.target && this.target.changeColor(this.activeColor); does is first check is this.target exists and then (if it exists) call it’s changeColor method, right? Sadly, it’s giving me some errors in my editor, so I’ll rather be using if(typeof this.target !== 'undefined'){this.target.changeColor(this.activeColor);} which might be overkill, but I think it’s preferrable.
  3. The code looks great in the post! But sadly I needed to delete the line numbers manually when I copied it, is there a chance to remove them here? (I guess we could also upload a .js file, but copy paste is easier and more accessible for everyone isn’t it?)

PS: for someone looking for a “quick and dirty” implementation, the bare minimum for making a layer swallow touch events seems to be:

var myLayer = cc.Layer.create();

myLayer.setTouchEnabled(true);
myLayer.setTouchPriority();        
myLayer.setTouchMode(cc.TOUCH_ONE_BY_ONE);
myLayer.onTouchBegan= function(touch) {
    return true;
};

parent.addChild(myLayer);

Happy to hear that you solved the problem

  1. (logTest || cc.log) wasn’t important, you can simply use cc.log or console.log
  2. you are right about it, for the test case, we don’t even need to check it
  3. Sadly the current version of our forum doesn’t support that yet, but I agree with you, and I will transfer your message.

Btw we have a new form of html5 test cases available on our site now: http://cocos2d-x.org/npm/cocos2d-html5/index.html, please check it out and tell us if it’s easier to use as a reference of code

Huabin

Huabin LING wrote:

  1. Sadly the current version of our forum doesn’t support that yet, but I agree with you, and I will transfer your message.
    I see. Even still, I wonder how you are formatting the text like that. Since I’m using “pre” tags for my code examples and they look fine (althought not highlighted). What method are you using?

Huabin LING wrote:

Btw we have a new form of html5 test cases available on our site now: http://cocos2d-x.org/npm/cocos2d-html5/index.html, please check it out and tell us if it’s easier to use as a reference of code

That indeed looks helpful!

PS: for those who will stumble into this in the future, this article includes an explanation of the touch dispatchers:
http://www.cocos2d-x.org/cocos-docs/tutorial/parkour-game-with-javascript/chapter3/en

Hi, Sebastian

Thanks for the your feedback, for text formatting, use this
pre tag include a code tag which has a class named by the language name.
pre
code class=“javascript”
/code
/pre
just add the <>

Huabin

I see. It works similar to this plugin I use for my wordpress blog: https://github.com/aramk/crayon-syntax-highlighter

But I think I’ll leave my code comments unformatted for now, since it’s easier to copypaste them without having to delete the line numbers by hand.

ok i am so glad it all worked. Basically any layer that needs to have touch swallow needs to setTouchPriority with a lower TP value than the layers beneath it.

Also, since menu has a default touch value of –128, what I did was to set menu’s TP to the TP of the layer that it is residing in.

P.s. Sebastian, I could highlight the codes without the line numbers. Using Mac Chrome.

Hey it seems like in cocos2d-x version 3.10, cc.c4f is not supported and i can not setTouchEnabled(true) to a layer. while compiling your above code i got many errors. i solved the color issue by replacing cc.c4f to cc.color but i dont know how to use setTouchEnabled on layers. Plz help