Physics.Arcade.sort has a new property 'sortDirection'. If not specified it will use World.sortDirection. If the Group given as the first parameter has its physicsSortDirection property set that will override any other setting.

Physics.Arcade.sort now calls one of four functions: sortLeftRight, sortRightLeft, sortTopBottom and sortBottomTop. Each of which takes 2 Sprites as arguments.

Physics.Arcade.sort now doesn't bail out if the Group contains a mixture of physics and non-physics enabled objects, as the Group hash is now only ever populated with physics enabled objects. Also the sort comparison functions no longer return -1 if the bodies are invalid, but zero instead (#1721)
This commit is contained in:
photonstorm 2015-04-13 16:28:14 +01:00
parent 35bfe5fb2a
commit 432516fa0f
2 changed files with 146 additions and 67 deletions

View file

@ -247,6 +247,8 @@ Version 2.3.1 - "Katar" - in dev
### New Features
* Tilemap.getTileWorldXY has a new optional parameter: `nonNull` which if set makes it behave in the same way as `getTile` does (thanks @GGAlanSmithee #1722)
* Group.hash is an array (previously available as `Group._hash`, but protected) into which you can add any of its children via `Group.addToHash` and `Group.removeFromHash`. Only children of the Group can be added to and removed from the hash. The hash is used automatically by Arcade Physics in order to perform non z-index based destructive sorting. However if you don't use Arcade Physics, or it isn't a physics enabled Group, then you can use the hash to perform your own sorting and filtering of Group children without touching their z-index (and therefore display draw order).
* Group.physicsSortDirection is a new property allowing you to set a custom sort direction for Arcade Physics Sprites within the Group hash. Previously Arcade Physics used one single sort direction (defined on `Phaser.Physics.Arcade.sortDirection`) but this change allows you to specifically control how each and every Group is sorted, so you can now combine tall and wide Groups with narrow and thin in a single system.
### Updates
@ -255,6 +257,11 @@ Version 2.3.1 - "Katar" - in dev
* Color.webToColor and Color.updateColor now updates the `out.color` and `out.color32` properties (thanks @cuixiping #1728)
* Tilemap.createFromObjects has been updated for Tiled 0.11 and can now look-up object layers based on id, uid or name. It will also now copy over Sprite scaling properties if set (thanks @mandarinx #1738)
* Graphics.drawPolygon can now accept a Phaser.Polygon or PIXI.Polygon object, as well as a points array (#1712)
* Phaser.Physics hooks added in for MatterJS support (coming soon)
* Body.destroy now automatically calls `Group.removeFromHash`.
* Physics.Arcade.sort has a new property 'sortDirection'. If not specified it will use World.sortDirection. If the Group given as the first parameter has its `physicsSortDirection` property set that will override any other setting.
* Physics.Arcade.sort now calls one of four functions: sortLeftRight, sortRightLeft, sortTopBottom and sortBottomTop. Each of which takes 2 Sprites as arguments.
* Physics.Arcade.sort now doesn't bail out if the Group contains a mixture of physics and non-physics enabled objects, as the Group hash is now only ever populated with physics enabled objects. Also the sort comparison functions no longer return -1 if the bodies are invalid, but zero instead (#1721)
### Bug Fixes

View file

@ -215,8 +215,11 @@ Phaser.Physics.Arcade.prototype = {
/**
* Creates an Arcade Physics body on the given game object.
*
* A game object can only have 1 physics body active at any one time, and it can't be changed until the body is nulled.
*
* When you add an Arcade Physics body to an object it will automatically add the object into its parent Groups hash array.
*
* @method Phaser.Physics.Arcade#enableBody
* @param {object} object - The game object to create the physics body on. A body will only be created if this object has a null `body` property.
*/
@ -225,6 +228,11 @@ Phaser.Physics.Arcade.prototype = {
if (object.hasOwnProperty('body') && object.body === null)
{
object.body = new Phaser.Physics.Arcade.Body(object);
if (object.parent && object.parent instanceof Phaser.Group)
{
object.parent.addToHash(object);
}
}
},
@ -278,7 +286,6 @@ Phaser.Physics.Arcade.prototype = {
}
else if (drag)
{
// var _drag = drag * this.game.time.physicsElapsed;
drag *= this.game.time.physicsElapsed;
if (velocity - drag > 0)
@ -425,71 +432,132 @@ Phaser.Physics.Arcade.prototype = {
},
/**
* This method will sort a Groups _hash array based on the sortDirection property.
*
* Each function should return -1 if `a > b`, 1 if `a < b` or 0 if `a === b`.
* A Sort function for sorting two bodies based on a LEFT to RIGHT sort direction.
*
* This is called automatically by World.sort
*
* @method sortLeftRight
* @param {Phaser.Sprite} a - The first Sprite to test. The Sprite must have an Arcade Physics Body.
* @param {Phaser.Sprite} b - The second Sprite to test. The Sprite must have an Arcade Physics Body.
* @return {integer} A negative value if `a > b`, a positive value if `a < b` or 0 if `a === b` or the bodies are invalid.
*/
sortLeftRight: function (a, b) {
if (!a.body || !b.body)
{
return 0;
}
return a.body.x - b.body.x;
},
/**
* A Sort function for sorting two bodies based on a RIGHT to LEFT sort direction.
*
* This is called automatically by World.sort
*
* @method sortRightLeft
* @param {Phaser.Sprite} a - The first Sprite to test. The Sprite must have an Arcade Physics Body.
* @param {Phaser.Sprite} b - The second Sprite to test. The Sprite must have an Arcade Physics Body.
* @return {integer} A negative value if `a > b`, a positive value if `a < b` or 0 if `a === b` or the bodies are invalid.
*/
sortRightLeft: function (a, b) {
if (!a.body || !b.body)
{
return 0;
}
return b.body.x - a.body.x;
},
/**
* A Sort function for sorting two bodies based on a TOP to BOTTOM sort direction.
*
* This is called automatically by World.sort
*
* @method sortTopBottom
* @param {Phaser.Sprite} a - The first Sprite to test. The Sprite must have an Arcade Physics Body.
* @param {Phaser.Sprite} b - The second Sprite to test. The Sprite must have an Arcade Physics Body.
* @return {integer} A negative value if `a > b`, a positive value if `a < b` or 0 if `a === b` or the bodies are invalid.
*/
sortTopBottom: function (a, b) {
if (!a.body || !b.body)
{
return 0;
}
return a.body.y - b.body.y;
},
/**
* A Sort function for sorting two bodies based on a BOTTOM to TOP sort direction.
*
* This is called automatically by World.sort
*
* @method sortBottomTop
* @param {Phaser.Sprite} a - The first Sprite to test. The Sprite must have an Arcade Physics Body.
* @param {Phaser.Sprite} b - The second Sprite to test. The Sprite must have an Arcade Physics Body.
* @return {integer} A negative value if `a > b`, a positive value if `a < b` or 0 if `a === b` or the bodies are invalid.
*/
sortBottomTop: function (a, b) {
if (!a.body || !b.body)
{
return 0;
}
return b.body.y - a.body.y;
},
/**
* This method will sort a Groups hash array.
*
* If the Group has `physicsSortDirection` set it will use the sort direction defined.
*
* Otherwise if the sortDirection parameter is undefined, or Group.physicsSortDirection is null, it will use Phaser.Physics.Arcade.sortDirection.
*
* By changing Group.physicsSortDirection you can customise each Group to sort in a different order.
*
* @method sort
* @protected
* @param {Phaser.Group} group - The Group to sort.
* @param {integer} [sortDirection] - The sort direction used to sort this Group.
*/
sort: function (group) {
sort: function (group, sortDirection) {
if (this.sortDirection === Phaser.Physics.Arcade.LEFT_RIGHT)
if (group.physicsSortDirection !== null)
{
sortDirection = group.physicsSortDirection;
}
else
{
if (typeof sortDirection === 'undefined') { sortDirection = this.sortDirection; }
}
if (sortDirection === Phaser.Physics.Arcade.LEFT_RIGHT)
{
// Game world is say 2000x600 and you start at 0
group._hash.sort(function(a, b) {
if (!a.body || !b.body)
{
return -1;
}
return a.body.x - b.body.x;
});
group.hash.sort(this.sortLeftRight);
}
else if (this.sortDirection === Phaser.Physics.Arcade.RIGHT_LEFT)
else if (sortDirection === Phaser.Physics.Arcade.RIGHT_LEFT)
{
// Game world is say 2000x600 and you start at 2000
group._hash.sort(function(a, b) {
if (!a.body || !b.body)
{
return -1;
}
return b.body.x - a.body.x;
});
group.hash.sort(this.sortRightLeft);
}
else if (this.sortDirection === Phaser.Physics.Arcade.TOP_BOTTOM)
else if (sortDirection === Phaser.Physics.Arcade.TOP_BOTTOM)
{
// Game world is say 800x2000 and you start at 0
group._hash.sort(function(a, b) {
if (!a.body || !b.body)
{
return -1;
}
return a.body.y - b.body.y;
});
group.hash.sort(this.sortTopBottom);
}
else if (this.sortDirection === Phaser.Physics.Arcade.BOTTOM_TOP)
else if (sortDirection === Phaser.Physics.Arcade.BOTTOM_TOP)
{
// Game world is say 800x2000 and you start at 2000
group._hash.sort(function(a, b) {
if (!a.body || !b.body)
{
return -1;
}
return b.body.y - a.body.y;
});
group.hash.sort(this.sortBottomTop);
}
},
@ -636,63 +704,67 @@ Phaser.Physics.Arcade.prototype = {
return;
}
var body;
if (this.skipQuadTree || sprite.body.skipQuadTree)
{
for (var i = 0; i < group._hash.length; i++)
for (var i = 0; i < group.hash.length; i++)
{
// Skip duff entries - we can't check a non-existent sprite or one with no body
if (!group._hash[i] || !group._hash[i].exists || !group._hash[i].body)
if (!group.hash[i] || !group.hash[i].exists || !group.hash[i].body)
{
continue;
}
body = group.hash[i].body;
// Skip items either side of the sprite
if (this.sortDirection === Phaser.Physics.Arcade.LEFT_RIGHT)
{
if (sprite.body.right < group._hash[i].body.x)
if (sprite.body.right < body.x)
{
break;
}
else if (group._hash[i].body.right < sprite.body.x)
else if (body.right < sprite.body.x)
{
continue;
}
}
else if (this.sortDirection === Phaser.Physics.Arcade.RIGHT_LEFT)
{
if (sprite.body.x > group._hash[i].body.right)
if (sprite.body.x > body.right)
{
break;
}
else if (group._hash[i].body.x > sprite.body.right)
else if (body.x > sprite.body.right)
{
continue;
}
}
else if (this.sortDirection === Phaser.Physics.Arcade.TOP_BOTTOM)
{
if (sprite.body.bottom < group._hash[i].body.y)
if (sprite.body.bottom < body.y)
{
break;
}
else if (group._hash[i].body.bottom < sprite.body.y)
else if (body.bottom < sprite.body.y)
{
continue;
}
}
else if (this.sortDirection === Phaser.Physics.Arcade.BOTTOM_TOP)
{
if (sprite.body.y > group._hash[i].body.bottom)
if (sprite.body.y > body.bottom)
{
break;
}
else if (group._hash[i].body.y > sprite.body.bottom)
else if (body.y > sprite.body.bottom)
{
continue;
}
}
this.collideSpriteVsSprite(sprite, group._hash[i], collideCallback, processCallback, callbackContext, overlapOnly);
this.collideSpriteVsSprite(sprite, group.hash[i], collideCallback, processCallback, callbackContext, overlapOnly);
}
}
else
@ -742,25 +814,25 @@ Phaser.Physics.Arcade.prototype = {
return;
}
for (var i = 0; i < group._hash.length; i++)
for (var i = 0; i < group.hash.length; i++)
{
// Skip duff entries - we can't check a non-existent sprite or one with no body
if (!group._hash[i] || !group._hash[i].exists || !group._hash[i].body)
if (!group.hash[i] || !group.hash[i].exists || !group.hash[i].body)
{
continue;
}
var object1 = group._hash[i];
var object1 = group.hash[i];
for (var j = i + 1; j < group._hash.length; j++)
for (var j = i + 1; j < group.hash.length; j++)
{
// Skip duff entries - we can't check a non-existent sprite or one with no body
if (!group._hash[j] || !group._hash[j].exists || !group._hash[j].body)
if (!group.hash[j] || !group.hash[j].exists || !group.hash[j].body)
{
continue;
}
var object2 = group._hash[j];
var object2 = group.hash[j];
// Skip items either side of the sprite
if (this.sortDirection === Phaser.Physics.Arcade.LEFT_RIGHT)