From d9080052c3d362c25058484546388e5396918df3 Mon Sep 17 00:00:00 2001 From: photonstorm Date: Wed, 19 Feb 2014 05:22:37 +0000 Subject: [PATCH] Disabled World bounds by default. Body.collides now takes a group level callback. Added Body.createBodyCallback and Body.createGroupCallback. --- examples/wip/contact1.js | 9 +++ examples/wip/contact2.js | 141 ++++++++++++++++++++++++++++++++++++++ src/gameobjects/Sprite.js | 2 - src/physics/Body.js | 116 ++++++++++++++++++++++++++----- src/physics/World.js | 51 ++++++++------ 5 files changed, 279 insertions(+), 40 deletions(-) create mode 100644 examples/wip/contact2.js diff --git a/examples/wip/contact1.js b/examples/wip/contact1.js index 1e889b20..53475b88 100644 --- a/examples/wip/contact1.js +++ b/examples/wip/contact1.js @@ -46,6 +46,7 @@ function create() { box.physicsEnabled = true; box.body.static = true; box.body.fixedRotation = true; + box.body.createBodyCallback(player.body, gotBox, this); } cursors = game.input.keyboard.createCursorKeys(); @@ -53,6 +54,14 @@ function create() { } +function gotBox(body1, body2, shape1, shape2) { + + console.log('gotBox'); + + body1.sprite.kill(); + +} + function update() { if (cursors.left.isDown) diff --git a/examples/wip/contact2.js b/examples/wip/contact2.js new file mode 100644 index 00000000..5b7e616b --- /dev/null +++ b/examples/wip/contact2.js @@ -0,0 +1,141 @@ + +var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render }); + +function preload() { + + game.load.spritesheet('dude', 'assets/games/starstruck/dude.png', 32, 48); + game.load.image('background', 'assets/games/starstruck/background2.png'); + game.load.image('box', 'assets/sprites/block.png'); + +} + +var player; +var facing = 'left'; +var jumpTimer = 0; +var cursors; +var jumpButton; +var boxes; + +function create() { + + game.stage.backgroundColor = '#000000'; + + bg = game.add.tileSprite(0, 0, 800, 600, 'background'); + bg.fixedToCamera = true; + + game.physics.gravity.y = 20; + game.physics.friction = 0.5; + game.physics.setBoundsToWorld(); + + var playerCG = game.physics.createCollisionGroup(); + var boxCG = game.physics.createCollisionGroup(); + + player = game.add.sprite(50, 400, 'dude'); + player.physicsEnabled = true; + player.body.fixedRotation = true; + player.body.setCollisionGroup(playerCG); + + player.animations.add('left', [0, 1, 2, 3], 10, true); + player.animations.add('turn', [4], 20, true); + player.animations.add('right', [5, 6, 7, 8], 10, true); + + boxes = game.add.group(); + + for (var i = 0; i < 10; i++) + { + var box = boxes.create(200 + (i * 50), 550, 'box'); + box.scale.set(0.5); + box.physicsEnabled = true; + box.body.setCollisionGroup(boxCG); + box.body.collides(playerCG); + box.body.fixedRotation = true; + } + + // Because player is creating the collides callback, the parameter order will be: callback (playerBody, boxBody, playerShape, boxShape) + player.body.collides(boxCG, gotBox, this); + + + cursors = game.input.keyboard.createCursorKeys(); + jumpButton = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR); + +} + +function gotBox(body1, body2, shape1, shape2) { + + console.log('gotBox'); + + body2.sprite.kill(); + +} + +function update() { + + if (cursors.left.isDown) + { + player.body.moveLeft(200); + + if (facing != 'left') + { + player.animations.play('left'); + facing = 'left'; + } + } + else if (cursors.right.isDown) + { + player.body.moveRight(200); + + if (facing != 'right') + { + player.animations.play('right'); + facing = 'right'; + } + } + else + { + player.body.velocity.x = 0; + + if (facing != 'idle') + { + player.animations.stop(); + + if (facing == 'left') + { + player.frame = 0; + } + else + { + player.frame = 5; + } + + facing = 'idle'; + } + } + + if (jumpButton.isDown && game.time.now > jumpTimer && checkIfCanJump()) + { + player.body.moveUp(300); + jumpTimer = game.time.now + 750; + } + +} + +function checkIfCanJump(){ +var yAxis = p2.vec2.fromValues(0,1); +var result = false; +for(var i=0; i 0.5) result = true; + } +} +return result; +} + + +function render () { + + game.debug.renderPhysicsBody(player.body); + +} diff --git a/src/gameobjects/Sprite.js b/src/gameobjects/Sprite.js index a4c14556..7e100c84 100644 --- a/src/gameobjects/Sprite.js +++ b/src/gameobjects/Sprite.js @@ -903,11 +903,9 @@ Object.defineProperty(Phaser.Sprite.prototype, "exists", { { // exists = false this._cache[6] = 0; - console.log('exists false'); if (this.body) { - console.log('exists false remove from world'); this.body.removeFromWorld(); } diff --git a/src/physics/Body.js b/src/physics/Body.js index b272a274..87f9a487 100644 --- a/src/physics/Body.js +++ b/src/physics/Body.js @@ -70,25 +70,46 @@ Phaser.Physics.Body = function (game, sprite, x, y, mass) { */ this.collideWorldBounds = true; + /** + * @property {Phaser.Signal} onImpact - Dispatched when the shape/s of this Body impact with another. The event will be sent 2 parameters, this Body and the impact Body. + */ + this.onImpact = new Phaser.Signal(); + /** * @property {array} collidesWith - Array of CollisionGroups that this Bodies shapes collide with. * @private */ this.collidesWith = []; + /** + * @property {array} _bodyCallbacks - Array of Body callbacks. + * @private + */ + this._bodyCallbacks = []; + /** + * @property {array} _bodyCallbackContext - Array of Body callback contexts. + * @private + */ + this._bodyCallbackContext = []; - // this.onAdded = new Phaser.Signal(); - // this.onRemoved = new Phaser.Signal(); + /** + * @property {array} _groupCallbacks - Array of Group callbacks. + * @private + */ + this._groupCallbacks = []; + + /** + * @property {array} _bodyCallbackContext - Array of Grouo callback contexts. + * @private + */ + this._groupCallbackContext = []; // Set-up the default shape if (sprite) { this.setRectangleFromSprite(sprite); - // Default collision mask - // this.data.shapes[0].collisionMask = this.game.physics.boundsCollisionGroup.mask; - this.game.physics.addBody(this); } @@ -96,25 +117,79 @@ Phaser.Physics.Body = function (game, sprite, x, y, mass) { Phaser.Physics.Body.prototype = { + /** + * Sets a callback to be fired any time this Body impacts with the given Body. The impact test is performed against body.id values. + * The callback will be sent 4 parameters: This body, the body that impacted, the Shape in this body and the shape in the impacting body. + * + * @method Phaser.Physics.Body#createBodyCallback + * @param {Phaser.Physics.Body} body - The Body to send impact events for. + * @param {function} callback - The callback to fire on impact. Set to null to clear a previously set callback. + * @param {object} callbackContext - The context under which the callback will fire. + */ + createBodyCallback: function (body, callback, callbackContext) { + + this._bodyCallbacks[body.data.id] = callback; + this._bodyCallbackContext[body.data.id] = callbackContext; + + }, + /** * Sets the given CollisionGroup to be the collision group for all shapes in this Body, unless a shape is specified. * + * @method Phaser.Physics.Body#createGroupCallback + * @param {Phaser.Physics.CollisionGroup} group - The Group to send impact events for. + * @param {function} callback - The callback to fire on impact. Set to null to clear a previously set callback. + * @param {object} callbackContext - The context under which the callback will fire. + */ + createGroupCallback: function (group, callback, callbackContext) { + + this._groupCallbacks[group.mask] = callback; + this._groupCallbackContext[group.mask] = callbackContext; + + }, + + getCollisionMask: function () { + + var mask = 0; + + if (this.collideWorldBounds) + { + mask = this.game.physics.boundsCollisionGroup.mask; + } + + for (var i = 0; i < this.collidesWith.length; i++) + { + mask = mask | this.collidesWith[i].mask; + } + + return mask; + + }, + + /** + * Sets the given CollisionGroup to be the collision group for all shapes in this Body, unless a shape is specified. + * This also resets the collisionMask. + * * @method Phaser.Physics.Body#setCollisionGroup * @param {Phaser.Physics.CollisionGroup|array} group - The Collision Group that this Bodies shapes will use. * @param {p2.Shape} [shape] - An optional Shape. If not provided the collision group will be added to all Shapes in this Body. */ setCollisionGroup: function (group, shape) { + var mask = this.getCollisionMask(); + if (typeof shape === 'undefined') { for (var i = this.data.shapes.length - 1; i >= 0; i--) { this.data.shapes[i].collisionGroup = group.mask; + this.data.shapes[i].collisionMask = mask; } } else { shape.collisionGroup = group.mask; + shapes.collisionMask = mask; } }, @@ -157,6 +232,11 @@ Phaser.Physics.Body.prototype = { } } + if (clearGroup) + { + this.collidesWith.length = 0; + } + }, /** @@ -164,9 +244,11 @@ Phaser.Physics.Body.prototype = { * * @method Phaser.Physics.Body#collides * @param {Phaser.Physics.CollisionGroup|array} group - The Collision Group or Array of Collision Groups that this Bodies shapes will collide with. + * @param {function} [callback] - Optional callback that will be triggered when this Body impacts with the given Group. + * @param {object} [callbackContext] - The context under which the callback will be called. * @param {p2.Shape} [shape] - An optional Shape. If not provided the collision mask will be added to all Shapes in this Body. */ - collides: function (group, shape) { + collides: function (group, callback, callbackContext, shape) { if (Array.isArray(group)) { @@ -175,6 +257,11 @@ Phaser.Physics.Body.prototype = { if (this.collidesWith.indexOf(group[i]) === -1) { this.collidesWith.push(group[i]); + + if (callback) + { + this.createGroupCallback(group[i], callback, callbackContext); + } } } } @@ -183,20 +270,15 @@ Phaser.Physics.Body.prototype = { if (this.collidesWith.indexOf(group) === -1) { this.collidesWith.push(group); + + if (callback) + { + this.createGroupCallback(group, callback, callbackContext); + } } } - var mask = 0; - - if (this.collideWorldBounds) - { - mask = this.game.physics.boundsCollisionGroup.mask; - } - - for (var i = 0; i < this.collidesWith.length; i++) - { - mask = mask | this.collidesWith[i].mask; - } + var mask = this.getCollisionMask(); if (typeof shape === 'undefined') { diff --git a/src/physics/World.js b/src/physics/World.js index 427e38c6..845bb18a 100644 --- a/src/physics/World.js +++ b/src/physics/World.js @@ -152,7 +152,9 @@ Phaser.Physics.World = function (game, config) { this.boundsCollisionGroup = new Phaser.Physics.CollisionGroup(2); this.boundsCollidesWith = []; - this.setBoundsToWorld(true, true, true, true, false); + // Group vs. Group callbacks + + // this.setBoundsToWorld(true, true, true, true, false); }; @@ -167,8 +169,6 @@ Phaser.Physics.World.prototype = { */ postStepHandler: function (event) { - // console.log('postStep', event); - }, /** @@ -205,16 +205,31 @@ Phaser.Physics.World.prototype = { */ impactHandler: function (event) { - if (event.bodyA.id > 1 && event.bodyB.id > 1) + if (event.bodyA.parent && event.bodyB.parent) { - console.log('impactHandler'); - console.log(event); - console.log(event.bodyA.parent.sprite.key); + // Body vs. Body callbacks + var a = event.bodyA.parent; + var b = event.bodyB.parent; - if (event.bodyB.parent.sprite.key == 'box') + if (a._bodyCallbacks[event.bodyB.id]) { - console.log(event.bodyB.parent.sprite.key + ' KILLED'); - event.bodyB.parent.sprite.kill(); + a._bodyCallbacks[event.bodyB.id].call(a._bodyCallbackContext[event.bodyB.id], a, b, event.shapeA, event.shapeB); + } + + if (b._bodyCallbacks[event.bodyA.id]) + { + b._bodyCallbacks[event.bodyA.id].call(b._bodyCallbackContext[event.bodyA.id], b, a, event.shapeB, event.shapeA); + } + + // Body vs. Group callbacks + if (a._groupCallbacks[event.shapeB.collisionGroup]) + { + a._groupCallbacks[event.shapeB.collisionGroup].call(a._groupCallbackContext[event.shapeB.collisionGroup], a, b, event.shapeA, event.shapeB); + } + + if (b._groupCallbacks[event.shapeA.collisionGroup]) + { + b._groupCallbacks[event.shapeA.collisionGroup].call(b._groupCallbackContext[event.shapeA.collisionGroup], b, a, event.shapeB, event.shapeA); } } @@ -231,13 +246,11 @@ Phaser.Physics.World.prototype = { if (event.bodyA.id > 1 && event.bodyB.id > 1) { - console.log('beginContactHandler'); - console.log(event.bodyA.parent.sprite.key); - console.log(event.bodyB.parent.sprite.key); + // console.log('beginContactHandler'); + // console.log(event.bodyA.parent.sprite.key); + // console.log(event.bodyB.parent.sprite.key); } - event = {}; - }, /** @@ -249,16 +262,12 @@ Phaser.Physics.World.prototype = { */ endContactHandler: function (event) { - console.log('endContactHandler'); - console.log(event); if (event.bodyA.id > 1 && event.bodyB.id > 1) { - console.log('endContactHandler'); - console.log(event); + // console.log('endContactHandler'); + // console.log(event); } - event = {}; - }, /**