mirror of
https://github.com/photonstorm/phaser
synced 2025-02-17 06:28:30 +00:00
P2 collision groups and callbacks working as expected, new example done.
This commit is contained in:
parent
94448d2497
commit
0584d3eadf
4 changed files with 267 additions and 64 deletions
124
examples/p2 physics/collision groups.js
Normal file
124
examples/p2 physics/collision groups.js
Normal file
|
@ -0,0 +1,124 @@
|
|||
|
||||
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update, render: render });
|
||||
|
||||
function preload() {
|
||||
|
||||
game.load.image('stars', 'assets/misc/starfield.jpg');
|
||||
game.load.spritesheet('ship', 'assets/sprites/humstar.png', 32, 32);
|
||||
game.load.image('panda', 'assets/sprites/spinObj_01.png');
|
||||
game.load.image('sweet', 'assets/sprites/spinObj_06.png');
|
||||
|
||||
}
|
||||
|
||||
var ship;
|
||||
var starfield;
|
||||
var cursors;
|
||||
|
||||
function create() {
|
||||
|
||||
// Enable P2
|
||||
game.physics.startSystem(Phaser.Physics.P2JS);
|
||||
|
||||
// Turn on impact events for the world, without this we get no collision callbacks
|
||||
game.physics.p2.setImpactEvents(true);
|
||||
|
||||
// Create our collision groups. One for the player, one for the pandas
|
||||
var playerCollisionGroup = game.physics.p2.createCollisionGroup();
|
||||
var pandaCollisionGroup = game.physics.p2.createCollisionGroup();
|
||||
|
||||
// This part is vital if you want the objects with their own collision groups to still collide with the world bounds
|
||||
// (which we do) - what this does is adjust the bounds to use its own collision group.
|
||||
game.physics.p2.updateBoundsCollisionGroup();
|
||||
|
||||
starfield = game.add.tileSprite(0, 0, 800, 600, 'stars');
|
||||
starfield.fixedToCamera = true;
|
||||
|
||||
var pandas = game.add.group();
|
||||
pandas.enableBody = true;
|
||||
pandas.physicsBodyType = Phaser.Physics.P2JS;
|
||||
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
var panda = pandas.create(game.world.randomX, game.world.randomY, 'panda');
|
||||
panda.body.setRectangle(40, 40);
|
||||
|
||||
// Tell the panda to use the pandaCollisionGroup
|
||||
panda.body.setCollisionGroup(pandaCollisionGroup);
|
||||
|
||||
// Pandas will collide against themselves and the player
|
||||
// If you don't set this they'll not collide with anything.
|
||||
// The first parameter is either an array or a single collision group.
|
||||
panda.body.collides([pandaCollisionGroup, playerCollisionGroup]);
|
||||
}
|
||||
|
||||
// Create our ship sprite
|
||||
ship = game.add.sprite(200, 200, 'ship');
|
||||
ship.scale.set(2);
|
||||
ship.smoothed = false;
|
||||
ship.animations.add('fly', [0,1,2,3,4,5], 10, true);
|
||||
ship.play('fly');
|
||||
|
||||
game.physics.p2.enable(ship, false);
|
||||
ship.body.setCircle(28);
|
||||
|
||||
// Set the ships collision group
|
||||
ship.body.setCollisionGroup(playerCollisionGroup);
|
||||
|
||||
// The ship will collide with the pandas, and when it strikes one the hitPanda callback will fire, causing it to alpha out a bit
|
||||
// When pandas collide with each other, nothing happens to them.
|
||||
ship.body.collides(pandaCollisionGroup, hitPanda, this);
|
||||
|
||||
game.camera.follow(ship);
|
||||
|
||||
cursors = game.input.keyboard.createCursorKeys();
|
||||
|
||||
}
|
||||
|
||||
function hitPanda(body1, body2) {
|
||||
|
||||
// body1 is the space ship (as it's the body that owns the callback)
|
||||
// body2 is the body it impacted with, in this case our panda
|
||||
// As body2 is a Phaser.Physics.P2.Body object, you access its own (the sprite) via the sprite property:
|
||||
body2.sprite.alpha -= 0.1;
|
||||
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
||||
ship.body.setZeroVelocity();
|
||||
|
||||
if (cursors.left.isDown)
|
||||
{
|
||||
ship.body.moveLeft(200);
|
||||
}
|
||||
else if (cursors.right.isDown)
|
||||
{
|
||||
ship.body.moveRight(200);
|
||||
}
|
||||
|
||||
if (cursors.up.isDown)
|
||||
{
|
||||
ship.body.moveUp(200);
|
||||
}
|
||||
else if (cursors.down.isDown)
|
||||
{
|
||||
ship.body.moveDown(200);
|
||||
}
|
||||
|
||||
if (!game.camera.atLimit.x)
|
||||
{
|
||||
starfield.tilePosition.x += (ship.body.velocity.x * 16) * game.time.physicsElapsed;
|
||||
}
|
||||
|
||||
if (!game.camera.atLimit.y)
|
||||
{
|
||||
starfield.tilePosition.y += (ship.body.velocity.y * 16) * game.time.physicsElapsed;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function render() {
|
||||
|
||||
game.debug.text('Collide with the Pandas!', 32, 32);
|
||||
|
||||
}
|
|
@ -16,27 +16,19 @@ var cursors;
|
|||
|
||||
function create() {
|
||||
|
||||
game.world.setBounds(0, 0, 1600, 1200);
|
||||
|
||||
game.physics.startSystem(Phaser.Physics.P2JS);
|
||||
game.physics.p2.defaultRestitution = 0.9;
|
||||
|
||||
starfield = game.add.tileSprite(0, 0, 800, 600, 'stars');
|
||||
starfield.fixedToCamera = true;
|
||||
|
||||
balls = game.add.group();
|
||||
balls.enableBody = true;
|
||||
// balls.enableBodyDebug = true;
|
||||
balls.physicsBodyType = Phaser.Physics.P2JS;
|
||||
var panda = game.add.sprite(game.world.randomX, game.world.randomY, 'panda');
|
||||
game.physics.p2.enable(panda, false);
|
||||
panda.body.setRectangle(40, 40, 0, 0);
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
var panda = balls.create(game.world.randomX, game.world.randomY, 'panda');
|
||||
panda.body.setCircle(26);
|
||||
|
||||
var sweet = balls.create(game.world.randomX, game.world.randomY, 'sweet');
|
||||
sweet.body.setCircle(28);
|
||||
}
|
||||
var sweet = game.add.sprite(game.world.randomX, game.world.randomY, 'sweet');
|
||||
game.physics.p2.enable(sweet, false);
|
||||
sweet.body.setRectangle(40, 40, 0, 0);
|
||||
|
||||
ship = game.add.sprite(200, 200, 'ship');
|
||||
ship.scale.set(2);
|
||||
|
@ -50,13 +42,22 @@ function create() {
|
|||
|
||||
game.camera.follow(ship);
|
||||
|
||||
// ship.body.onBeginContact.add(hitBall, this);
|
||||
// Here we create a Body specific callback
|
||||
ship.body.createBodyCallback(panda, hitPanda, this);
|
||||
|
||||
// And before this will happen, we need to turn on impact events for the world
|
||||
game.physics.p2.setImpactEvents(true);
|
||||
|
||||
cursors = game.input.keyboard.createCursorKeys();
|
||||
|
||||
}
|
||||
|
||||
function hitBall(body) {
|
||||
function hitPanda(body1, body2) {
|
||||
|
||||
// body1 is the space ship (as it's the body that owns the callback)
|
||||
// body2 is the body it impacted with, in this case our panda
|
||||
// As body2 is a Phaser.Physics.P2.Body object, you access its own (the sprite) via the sprite property:
|
||||
body2.sprite.alpha -= 0.1;
|
||||
|
||||
}
|
||||
|
||||
|
@ -96,6 +97,6 @@ function update() {
|
|||
|
||||
function render() {
|
||||
|
||||
game.debug.text('World bodies: ' + game.physics.p2.total, 32, 32);
|
||||
game.debug.text('Collide with the Panda!', 32, 32);
|
||||
|
||||
}
|
|
@ -45,7 +45,7 @@ Phaser.Physics.P2.Body = function (game, sprite, x, y, mass) {
|
|||
/**
|
||||
* @property {number} type - The type of physics system this body belongs to.
|
||||
*/
|
||||
this.type = Phaser.Physics.P2;
|
||||
this.type = Phaser.Physics.P2JS;
|
||||
|
||||
/**
|
||||
* @property {Phaser.Point} offset - The offset of the Physics Body from the Sprite x/y position.
|
||||
|
@ -114,28 +114,28 @@ Phaser.Physics.P2.Body = function (game, sprite, x, y, mass) {
|
|||
this.safeRemove = false;
|
||||
|
||||
/**
|
||||
* @property {array} _bodyCallbacks - Array of Body callbacks.
|
||||
* @property {object} _bodyCallbacks - Array of Body callbacks.
|
||||
* @private
|
||||
*/
|
||||
this._bodyCallbacks = [];
|
||||
this._bodyCallbacks = {};
|
||||
|
||||
/**
|
||||
* @property {array} _bodyCallbackContext - Array of Body callback contexts.
|
||||
* @property {object} _bodyCallbackContext - Array of Body callback contexts.
|
||||
* @private
|
||||
*/
|
||||
this._bodyCallbackContext = [];
|
||||
this._bodyCallbackContext = {};
|
||||
|
||||
/**
|
||||
* @property {array} _groupCallbacks - Array of Group callbacks.
|
||||
* @property {object} _groupCallbacks - Array of Group callbacks.
|
||||
* @private
|
||||
*/
|
||||
this._groupCallbacks = [];
|
||||
this._groupCallbacks = {};
|
||||
|
||||
/**
|
||||
* @property {array} _bodyCallbackContext - Array of Grouo callback contexts.
|
||||
* @property {object} _bodyCallbackContext - Array of Grouo callback contexts.
|
||||
* @private
|
||||
*/
|
||||
this._groupCallbackContext = [];
|
||||
this._groupCallbackContext = {};
|
||||
|
||||
/**
|
||||
* @property {Phaser.Physics.P2.BodyDebug} debugBody - Reference to the debug body.
|
||||
|
@ -155,27 +155,41 @@ Phaser.Physics.P2.Body = function (game, sprite, x, y, mass) {
|
|||
Phaser.Physics.P2.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.
|
||||
* Sets a callback to be fired any time a shape in this Body impacts with a shape in 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.
|
||||
* Note that the impact event happens after collision resolution, so it cannot be used to prevent a collision from happening.
|
||||
* It also happens mid-step. So do not destroy a Body during this callback, instead set safeDestroy to true so it will be killed on the next preUpdate.
|
||||
*
|
||||
* @method Phaser.Physics.P2.Body#createBodyCallback
|
||||
* @param {Phaser.Physics.P2.Body|p2.Body} body - The Body to send impact events for.
|
||||
* @param {Phaser.Sprite|Phaser.TileSprite|Phaser.Physics.P2.Body|p2.Body} object - The object 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) {
|
||||
createBodyCallback: function (object, callback, callbackContext) {
|
||||
|
||||
if (body instanceof Phaser.Physics.P2.Body)
|
||||
var id = -1;
|
||||
|
||||
if (object['id'])
|
||||
{
|
||||
this._bodyCallbacks[body.data.id] = callback;
|
||||
this._bodyCallbackContext[body.data.id] = callbackContext;
|
||||
id = object.id;
|
||||
}
|
||||
else if (body instanceof p2.Body)
|
||||
else if (object['body'])
|
||||
{
|
||||
this._bodyCallbacks[body.id] = callback;
|
||||
this._bodyCallbackContext[body.id] = callbackContext;
|
||||
id = object.body.id;
|
||||
}
|
||||
|
||||
if (id > -1)
|
||||
{
|
||||
if (callback === null)
|
||||
{
|
||||
delete (this._bodyCallbacks[id]);
|
||||
delete (this._bodyCallbackContext[id]);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._bodyCallbacks[id] = callback;
|
||||
this._bodyCallbackContext[id] = callbackContext;
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
@ -194,8 +208,16 @@ Phaser.Physics.P2.Body.prototype = {
|
|||
*/
|
||||
createGroupCallback: function (group, callback, callbackContext) {
|
||||
|
||||
this._groupCallbacks[group.mask] = callback;
|
||||
this._groupCallbackContext[group.mask] = callbackContext;
|
||||
if (callback === null)
|
||||
{
|
||||
delete (this._groupCallbacks[group.mask]);
|
||||
delete (this._groupCallbacksContext[group.mask]);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._groupCallbacks[group.mask] = callback;
|
||||
this._groupCallbackContext[group.mask] = callbackContext;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
@ -228,7 +250,7 @@ Phaser.Physics.P2.Body.prototype = {
|
|||
* This also resets the collisionMask.
|
||||
*
|
||||
* @method Phaser.Physics.P2.Body#setCollisionGroup
|
||||
* @param {Phaser.Physics.CollisionGroup|array} group - The Collision Group that this Bodies shapes will use.
|
||||
* @param {Phaser.Physics.CollisionGroup} 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) {
|
||||
|
@ -246,7 +268,7 @@ Phaser.Physics.P2.Body.prototype = {
|
|||
else
|
||||
{
|
||||
shape.collisionGroup = group.mask;
|
||||
shapes.collisionMask = mask;
|
||||
shape.collisionMask = mask;
|
||||
}
|
||||
|
||||
},
|
||||
|
@ -902,14 +924,9 @@ Phaser.Physics.P2.Body.prototype = {
|
|||
else if (Array.isArray(points[0]))
|
||||
{
|
||||
path = points[0].slice(0);
|
||||
// for (var i = 0, len = points[0].length; i < len; i += 2)
|
||||
// {
|
||||
// path.push([points[0][i], points[0][i + 1]]);
|
||||
// }
|
||||
}
|
||||
else if (typeof points[0] === 'number')
|
||||
{
|
||||
// console.log('addPolygon --- We\'ve a list of numbers');
|
||||
// We've a list of numbers
|
||||
for (var i = 0, len = points.length; i < len; i += 2)
|
||||
{
|
||||
|
@ -917,10 +934,6 @@ Phaser.Physics.P2.Body.prototype = {
|
|||
}
|
||||
}
|
||||
|
||||
// console.log('addPolygon PATH pre');
|
||||
// console.log(path[1]);
|
||||
// console.table(path);
|
||||
|
||||
// top and tail
|
||||
var idx = path.length - 1;
|
||||
|
||||
|
@ -936,10 +949,6 @@ Phaser.Physics.P2.Body.prototype = {
|
|||
path[p][1] = this.world.pxmi(path[p][1]);
|
||||
}
|
||||
|
||||
// console.log('addPolygon PATH POST');
|
||||
// console.log(path[1]);
|
||||
// console.table(path);
|
||||
|
||||
result = this.data.fromPolygon(path, options);
|
||||
|
||||
this.shapeChanged();
|
||||
|
@ -1565,6 +1574,21 @@ Object.defineProperty(Phaser.Physics.P2.Body.prototype, "y", {
|
|||
|
||||
});
|
||||
|
||||
/**
|
||||
* @name Phaser.Physics.P2.Body#id
|
||||
* @property {number} id - The Body ID. Each Body that has been added to the World has a unique ID.
|
||||
* @readonly
|
||||
*/
|
||||
Object.defineProperty(Phaser.Physics.P2.Body.prototype, "id", {
|
||||
|
||||
get: function () {
|
||||
|
||||
return this.data.id;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* @name Phaser.Physics.P2.Body#debug
|
||||
* @property {boolean} debug - Enable or disable debug drawing of this body
|
||||
|
|
|
@ -148,8 +148,6 @@ Phaser.Physics.P2 = function (game, config) {
|
|||
|
||||
this.boundsCollidesWith = [];
|
||||
|
||||
// Group vs. Group callbacks
|
||||
|
||||
// By default we want everything colliding with everything
|
||||
this.setBoundsToWorld(true, true, true, true, false);
|
||||
|
||||
|
@ -417,6 +415,7 @@ Phaser.Physics.P2.prototype = {
|
|||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Sets the given material against the 4 bounds of this World.
|
||||
*
|
||||
|
@ -456,6 +455,35 @@ Phaser.Physics.P2.prototype = {
|
|||
|
||||
},
|
||||
|
||||
/**
|
||||
* By default the World will be set to collide everything with everything. The bounds of the world is a Body with 4 shapes, one for each face.
|
||||
* If you start to use your own collision groups then your objects will no longer collide with the bounds.
|
||||
* To fix this you need to adjust the bounds to use its own collision group first BEFORE changing your Sprites collision group.
|
||||
*
|
||||
* @method Phaser.Physics.P2#updateBoundsCollisionGroup
|
||||
* @param {boolean} [setCollisionGroup=true] - If true the Bounds will be set to use its own Collision Group.
|
||||
*/
|
||||
updateBoundsCollisionGroup: function (setCollisionGroup) {
|
||||
|
||||
if (typeof setCollisionGroup === 'undefined') { setCollisionGroup = true; }
|
||||
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
if (this._wallShapes[i])
|
||||
{
|
||||
if (setCollisionGroup)
|
||||
{
|
||||
this._wallShapes[i].collisionGroup = this.boundsCollisionGroup.mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
this._wallShapes[i].collisionGroup = this.everythingCollisionGroup.mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the bounds of the Physics world to match the given world pixel dimensions.
|
||||
* You can optionally set which 'walls' to create: left, right, top or bottom.
|
||||
|
@ -514,8 +542,6 @@ Phaser.Physics.P2.prototype = {
|
|||
if (setCollisionGroup)
|
||||
{
|
||||
this._wallShapes[0].collisionGroup = this.boundsCollisionGroup.mask;
|
||||
// this._wallShapes[0].collisionGroup = this.everythingCollisionGroup.mask;
|
||||
// this._wallShapes[0].collisionMask = this.everythingCollisionGroup.mask;
|
||||
}
|
||||
|
||||
this.bounds.addShape(this._wallShapes[0], [this.pxmi(-hw), 0], 1.5707963267948966 );
|
||||
|
@ -528,8 +554,6 @@ Phaser.Physics.P2.prototype = {
|
|||
if (setCollisionGroup)
|
||||
{
|
||||
this._wallShapes[1].collisionGroup = this.boundsCollisionGroup.mask;
|
||||
// this._wallShapes[1].collisionGroup = this.everythingCollisionGroup.mask;
|
||||
// this._wallShapes[1].collisionMask = this.everythingCollisionGroup.mask;
|
||||
}
|
||||
|
||||
this.bounds.addShape(this._wallShapes[1], [this.pxmi(hw), 0], -1.5707963267948966 );
|
||||
|
@ -542,8 +566,6 @@ Phaser.Physics.P2.prototype = {
|
|||
if (setCollisionGroup)
|
||||
{
|
||||
this._wallShapes[2].collisionGroup = this.boundsCollisionGroup.mask;
|
||||
// this._wallShapes[2].collisionGroup = this.everythingCollisionGroup.mask;
|
||||
// this._wallShapes[2].collisionMask = this.everythingCollisionGroup.mask;
|
||||
}
|
||||
|
||||
this.bounds.addShape(this._wallShapes[2], [0, this.pxmi(-hh)], -3.141592653589793 );
|
||||
|
@ -556,8 +578,6 @@ Phaser.Physics.P2.prototype = {
|
|||
if (setCollisionGroup)
|
||||
{
|
||||
this._wallShapes[3].collisionGroup = this.boundsCollisionGroup.mask;
|
||||
// this._wallShapes[3].collisionGroup = this.everythingCollisionGroup.mask;
|
||||
// this._wallShapes[3].collisionMask = this.everythingCollisionGroup.mask;
|
||||
}
|
||||
|
||||
this.bounds.addShape(this._wallShapes[3], [0, this.pxmi(hh)] );
|
||||
|
@ -937,12 +957,14 @@ Phaser.Physics.P2.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Creates a Collision Group for the wall shapes.
|
||||
* Creates a new Collision Group and optionally applies it to the given object.
|
||||
* Collision Groups are handled using bitmasks, therefore you have a fixed limit you can create before you need to re-use older groups.
|
||||
*
|
||||
* @method Phaser.Physics.P2#createCollisionGroup
|
||||
* @param {Phaser.Group|Phaser.Sprite} [object] - An optional Sprite or Group to apply the Collision Group to. If a Group is given it will be applied to all top-level children.
|
||||
* @protected
|
||||
*/
|
||||
createCollisionGroup: function () {
|
||||
createCollisionGroup: function (object) {
|
||||
|
||||
var bitmask = Math.pow(2, this._collisionGroupID);
|
||||
|
||||
|
@ -972,10 +994,42 @@ Phaser.Physics.P2.prototype = {
|
|||
|
||||
this.collisionGroups.push(group);
|
||||
|
||||
if (object)
|
||||
{
|
||||
this.setCollisionGroup(object, group);
|
||||
}
|
||||
|
||||
return group;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the given CollisionGroup to be the collision group for all shapes in this Body, unless a shape is specified.
|
||||
* Note that this resets the collisionMask and any previously set groups. See Body.collides() for appending them.
|
||||
*
|
||||
* @method Phaser.Physics.P2y#setCollisionGroup
|
||||
* @param {Phaser.Group|Phaser.Sprite} object - A Sprite or Group to apply the Collision Group to. If a Group is given it will be applied to all top-level children.
|
||||
* @param {Phaser.Physics.CollisionGroup} group - The Collision Group that this Bodies shapes will use.
|
||||
*/
|
||||
setCollisionGroup: function (object, group) {
|
||||
|
||||
if (object instanceof Phaser.Group)
|
||||
{
|
||||
for (var i = 0; i < object.total; i++)
|
||||
{
|
||||
if (object.children[i]['body'] && object.children[i]['body'].type === Phaser.Physics.P2JS)
|
||||
{
|
||||
object.children[i].body.setCollisionGroup(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
object.body.setCollisionGroup(group);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* @method Phaser.Physics.P2.prototype.createBody
|
||||
* @param {number} x - The x coordinate of Body.
|
||||
|
|
Loading…
Add table
Reference in a new issue