Puflo Posted November 10, 2017 Share Posted November 10, 2017 Box2D always calls contact callback twice. Here's an example: 185.50.68.103 Ship with collision category 2 (ship at left) calls contact callback once while ship with collision category 1 (default) calls it twice. I've been trying to fix this for weeks but couldn't find any solution in web, i really need you guys to help me. function create() { game.physics.startSystem(Phaser.Physics.BOX2D); game.stage.backgroundColor = '#2d2d2d'; // User-controlled ship ship1 = game.add.sprite(250, 300, 'ship'); game.physics.box2d.enable(ship1); ship1.body.setCircle(14); // Ship with collision category 2 (triggers contact callback only once, it shouldn't even trigger it) ship2 = game.add.sprite(200, 200, 'ship'); game.physics.box2d.enable(ship2); ship2.body.setCircle(14); ship2.body.setCollisionCategory(2); // Ship with collision category 1 *default, i guess* (triggers contact callback TWICE) ship3 = game.add.sprite(300, 200, 'ship'); game.physics.box2d.enable(ship3); ship3.body.setCircle(14); game.physics.box2d.setBoundsToWorld(true, true, true, true, false); ship1.body.setCategoryContactCallback(1, function(b1,b2,f1,f2,begin){ if (begin){ total += 1; hitText.text = 'Contact callback called '+total+' times'; console.log("CONTACT: ", b2) } }, this); cursors = game.input.keyboard.createCursorKeys(); game.add.text(5, 5, 'Use arrow keys to move.', { fill: '#ffffff', font: '14pt Arial' }); total = 0; hitText = game.add.text(5, 30, 'Contact callback called 0 times', { fill: '#ffffff', font: '14pt Arial' }); } function update() { if (cursors.left.isDown) { ship1.body.rotateLeft(300); } else if (cursors.right.isDown) { ship1.body.rotateRight(300); } else { ship1.body.setZeroRotation(); } if (cursors.up.isDown) { ship1.body.thrust(300); } else if (cursors.down.isDown) { ship1.body.reverse(300); } } function render() { game.debug.box2dWorld(); } Link to comment Share on other sites More sharing options...
Tom Atom Posted November 11, 2017 Share Posted November 11, 2017 Hi, try to combine setCollisionCategory with setCollisionMask. By default mask is 0xFFFF - collide with all other groups. Mask has to be set on both bodies (therefore setCollisionMask(1) on both ships). This works: function create() { game.physics.startSystem(Phaser.Physics.BOX2D); game.stage.backgroundColor = '#2d2d2d'; // User-controlled ship ship1 = game.add.sprite(250, 300, 'ship'); game.physics.box2d.enable(ship1); ship1.body.setCircle(14); ship1.body.setCollisionCategory(1); //ship1.body.setCollisionMask(2 + 4); // - will collide with ship2 (category 2) and ship3 (category 4) ship1.body.setCollisionMask(4); // - will collide only with ship2 (category 2) // Ship with collision category 2 (triggers contact callback only once) ship2 = game.add.sprite(200, 200, 'ship'); game.physics.box2d.enable(ship2); ship2.body.setCircle(14); ship2.body.setCollisionCategory(2); ship2.body.setCollisionMask(1); // Ship with collision category 1 *default, i guess* (triggers contact callback TWICE) ship3 = game.add.sprite(300, 200, 'ship'); game.physics.box2d.enable(ship3); ship3.body.setCircle(14); ship3.body.setCollisionCategory(4); ship3.body.setCollisionMask(1); game.physics.box2d.setBoundsToWorld(true, true, true, true, false); ship1.body.setCategoryContactCallback(1, function(b1,b2,f1,f2,begin){ if (begin){ total += 1; hitText.text = 'Contact callback called '+total+' times'; console.log("CONTACT: ", b2) } }, this); cursors = game.input.keyboard.createCursorKeys(); game.add.text(5, 5, 'Use arrow keys to move.', { fill: '#ffffff', font: '14pt Arial' }); total = 0; hitText = game.add.text(5, 30, 'Contact callback called 0 times', { fill: '#ffffff', font: '14pt Arial' }); } Puflo 1 Link to comment Share on other sites More sharing options...
Puflo Posted November 11, 2017 Author Share Posted November 11, 2017 3 hours ago, Tom Atom said: Hi, try to combine setCollisionCategory with setCollisionMask. By default mask is 0xFFFF - collide with all other groups. Mask has to be set on both bodies (therefore setCollisionMask(1) on both ships). This works: // ship1.body.setCollisionMask(2 + 4); // - will collide with ship2 (category 2) and ship3 (category 4) What exactly is 2 + 4 and why is collision mask 4 colliding with ship 2? Link to comment Share on other sites More sharing options...
Tom Atom Posted November 12, 2017 Share Posted November 12, 2017 First, sorry, this description was confusing: ship1.body.setCollisionMask(4); // - will collide only with ship2 (category 2) should be: ship1.body.setCollisionMask(4); // - will collide only with ship3 (category 4) What you are building in code is kind of collision grid like this: Take row, assign category to your object - like category 1 for ship1 and determine what all other categories you want it collide with (columns for ship2 and ship3). Then set collisionMask to sum. Puflo 1 Link to comment Share on other sites More sharing options...
Puflo Posted November 13, 2017 Author Share Posted November 13, 2017 I can't get ship2 and ship3 to collide world bounds, what i'm doing wrong? They collide each other but only ship1 is colliding world bounds. ship1 = game.add.sprite(200, 300, 'ship'); game.physics.box2d.enable(ship1); ship1.body.setCircle(14); ship1.body.setCollisionCategory(1); ship2 = game.add.sprite(200, 200, 'ship'); game.physics.box2d.enable(ship2); ship2.body.setCircle(14); ship2.body.setCollisionCategory(2); ship2.body.setCollisionMask(3); ship3 = game.add.sprite(300, 200, 'ship'); game.physics.box2d.enable(ship3); ship3.body.setCircle(14); ship3.body.setCollisionCategory(2); ship3.body.setCollisionMask(3); game.physics.box2d.setBoundsToWorld(true, true, true, true, 1, 3); // or 2,3 Edit: I made a hotfix for this, but i'd like to know why is the example above isn't working. game.physics.box2d.setBoundsToWorld(true, true, true, true); for (var i in game.physics.box2d.walls){ game.physics.box2d.walls[i].setCollisionCategory(2); game.physics.box2d.walls[i].setCollisionMask(3); } Link to comment Share on other sites More sharing options...
Tom Atom Posted November 15, 2017 Share Posted November 15, 2017 - in original example, you are using setBoundsToWorld incorrectly. This is from source doc: /** * Sets the bounds of the Physics world to match the Game.World dimensions. * You can optionally set which 'walls' to create: left, right, top or bottom. * * @method Phaser.Physics#setBoundsToWorld * @param {boolean} [left=true] - If true will create the left bounds wall. * @param {boolean} [right=true] - If true will create the right bounds wall. * @param {boolean} [top=true] - If true will create the top bounds wall. * @param {boolean} [bottom=true] - If true will create the bottom bounds wall. * @param {number} [collisionCategory=1] - The category (bitmask) to use for the walls. * @param {number} [collisionMask=0xFFFFFFFF] - The mask (bitmask) to use for the walls. */ setBoundsToWorld: function (left, right, top, bottom, collisionCategory, collisionMask) { ... it is again about category / mask. But you passed "false" as 5th parameter instead of category. See default values in code above. - for ship1 you are setting category to 1 and leaving collisionMask to default (which is 0xFFFF) - it says: "hey, I am from category 1 and I am colliding with EVERY other category". Which means: collide with bounds (category 1), other player-like ships (category 1) and both enemy ships (category 2) and everything else in physics world and any other category that may appear later... - for ship2 and ship3, you are setting category to 2 and mask to 3 (= 1+ 2). It says: "I am from cat. 2 and I am collidiong with category 2 and category 1) - ships will now collide with bounds (cat. 1), player ship (cat 1) and with each other (cat 2). It will not collide with asteroids, planets, etc. if they are category 4 or 8 or 16 or ... Link to comment Share on other sites More sharing options...
Recommended Posts