mirror of
https://github.com/photonstorm/phaser
synced 2024-11-23 13:13:43 +00:00
Arcade rect vs tilemap layer collision handling
This commit is contained in:
parent
fdc1af0cd2
commit
98ae8009e0
8 changed files with 365 additions and 0 deletions
|
@ -1,5 +1,48 @@
|
||||||
|
var SeparateTile = require('./tilemap/SeparateTile');
|
||||||
|
var TileIntersectsBody = require('./tilemap/TileIntersectsBody');
|
||||||
|
var ProcessTileCallbacks = require('./tilemap/ProcessTileCallbacks');
|
||||||
|
|
||||||
var CollideSpriteVsTilemapLayer = function (sprite, tilemapLayer, collideCallback, processCallback, callbackContext, overlapOnly)
|
var CollideSpriteVsTilemapLayer = function (sprite, tilemapLayer, collideCallback, processCallback, callbackContext, overlapOnly)
|
||||||
{
|
{
|
||||||
|
if (!sprite.body.enable)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mapData = tilemapLayer.getTilesWithinWorldXY(
|
||||||
|
sprite.body.position.x, sprite.body.position.y,
|
||||||
|
sprite.body.width, sprite.body.height
|
||||||
|
);
|
||||||
|
|
||||||
|
if (mapData.length === 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tile;
|
||||||
|
var tileWorldRect = { left: 0, right: 0, top: 0, bottom: 0 };
|
||||||
|
|
||||||
|
for (var i = 0; i < mapData.length; i++)
|
||||||
|
{
|
||||||
|
tile = mapData[i];
|
||||||
|
tileWorldRect.left = tilemapLayer.tileToWorldX(tile.x);
|
||||||
|
tileWorldRect.top = tilemapLayer.tileToWorldY(tile.y);
|
||||||
|
tileWorldRect.right = tileWorldRect.left + tile.width * tilemapLayer.scaleX;
|
||||||
|
tileWorldRect.bottom = tileWorldRect.top + tile.height * tilemapLayer.scaleY;
|
||||||
|
|
||||||
|
if (TileIntersectsBody(tileWorldRect, sprite.body)
|
||||||
|
&& (!processCallback || processCallback.call(callbackContext, sprite, tile))
|
||||||
|
&& ProcessTileCallbacks(tile)
|
||||||
|
&& (overlapOnly || SeparateTile(i, sprite.body, tile, tileWorldRect, tilemapLayer)))
|
||||||
|
{
|
||||||
|
this._total++;
|
||||||
|
|
||||||
|
if (collideCallback)
|
||||||
|
{
|
||||||
|
collideCallback.call(callbackContext, sprite, tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = CollideSpriteVsTilemapLayer;
|
module.exports = CollideSpriteVsTilemapLayer;
|
||||||
|
|
20
src/physics/arcade/inc/tilemap/ProcessTileCallbacks.js
Normal file
20
src/physics/arcade/inc/tilemap/ProcessTileCallbacks.js
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
var ProcessTileCallbacks = function (tile)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// TODO: port v2
|
||||||
|
// // Tilemap & tile callbacks take priority
|
||||||
|
// // A local callback always takes priority over a layer level callback
|
||||||
|
// if (tile.collisionCallback && !tile.collisionCallback.call(tile.collisionCallbackContext, body.sprite, tile))
|
||||||
|
// {
|
||||||
|
// // If it returns true then we can carry on, otherwise we should abort.
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// else if (typeof tile.layer.callbacks !== 'undefined' && tile.layer.callbacks[tile.index] && !tile.layer.callbacks[tile.index].callback.call(tile.layer.callbacks[tile.index].callbackContext, body.sprite, tile))
|
||||||
|
// {
|
||||||
|
// // If it returns true then we can carry on, otherwise we should abort.
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = ProcessTileCallbacks;
|
32
src/physics/arcade/inc/tilemap/ProcessTileSeparationX.js
Normal file
32
src/physics/arcade/inc/tilemap/ProcessTileSeparationX.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* Internal function to process the separation of a physics body from a tile.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @method Phaser.Physics.Arcade#processTileSeparationX
|
||||||
|
* @param {Phaser.Physics.Arcade.Body} body - The Body object to separate.
|
||||||
|
* @param {number} x - The x separation amount.
|
||||||
|
*/
|
||||||
|
var ProcessTileSeparationX = function (body, x)
|
||||||
|
{
|
||||||
|
if (x < 0)
|
||||||
|
{
|
||||||
|
body.blocked.left = true;
|
||||||
|
}
|
||||||
|
else if (x > 0)
|
||||||
|
{
|
||||||
|
body.blocked.right = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.position.x -= x;
|
||||||
|
|
||||||
|
if (body.bounce.x === 0)
|
||||||
|
{
|
||||||
|
body.velocity.x = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
body.velocity.x = -body.velocity.x * body.bounce.x;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = ProcessTileSeparationX;
|
32
src/physics/arcade/inc/tilemap/ProcessTileSeparationY.js
Normal file
32
src/physics/arcade/inc/tilemap/ProcessTileSeparationY.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* Internal function to process the separation of a physics body from a tile.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @method Phaser.Physics.Arcade#processTileSeparationY
|
||||||
|
* @param {Phaser.Physics.Arcade.Body} body - The Body object to separate.
|
||||||
|
* @param {number} y - The y separation amount.
|
||||||
|
*/
|
||||||
|
var ProcessTileSeparationY = function (body, y)
|
||||||
|
{
|
||||||
|
if (y < 0)
|
||||||
|
{
|
||||||
|
body.blocked.up = true;
|
||||||
|
}
|
||||||
|
else if (y > 0)
|
||||||
|
{
|
||||||
|
body.blocked.down = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.position.y -= y;
|
||||||
|
|
||||||
|
if (body.bounce.y === 0)
|
||||||
|
{
|
||||||
|
body.velocity.y = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
body.velocity.y = -body.velocity.y * body.bounce.y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = ProcessTileSeparationY;
|
94
src/physics/arcade/inc/tilemap/SeparateTile.js
Normal file
94
src/physics/arcade/inc/tilemap/SeparateTile.js
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
var TileCheckX = require('./TileCheckX');
|
||||||
|
var TileCheckY = require('./TileCheckY');
|
||||||
|
var TileIntersectsBody = require('./TileIntersectsBody');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The core separation function to separate a physics body and a tile.
|
||||||
|
*
|
||||||
|
* @param {Phaser.Physics.Arcade.Body} body - The Body object to separate.
|
||||||
|
* @param {Phaser.Tile} tile - The tile to collide against.
|
||||||
|
* @param {Phaser.TilemapLayer} tilemapLayer - The tilemapLayer to collide against.
|
||||||
|
* @return {boolean} Returns true if the body was separated, otherwise false.
|
||||||
|
*/
|
||||||
|
var SeparateTile = function (i, body, tile, tileWorldRect, tilemapLayer)
|
||||||
|
{
|
||||||
|
var tileLeft = tileWorldRect.left;
|
||||||
|
var tileTop = tileWorldRect.top;
|
||||||
|
var tileRight = tileWorldRect.right;
|
||||||
|
var tileBottom = tileWorldRect.bottom;
|
||||||
|
var faceHorizontal = tile.faceLeft || tile.faceRight;
|
||||||
|
var faceVertical = tile.faceTop || tile.faceBottom;
|
||||||
|
|
||||||
|
// We don't need to go any further if this tile doesn't actually have any colliding faces. This
|
||||||
|
// could happen if the tile was meant to be collided with re: a callback, but otherwise isn't
|
||||||
|
// needed for separation.
|
||||||
|
if (!faceHorizontal && !faceVertical)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ox = 0;
|
||||||
|
var oy = 0;
|
||||||
|
var minX = 0;
|
||||||
|
var minY = 1;
|
||||||
|
|
||||||
|
if (body.deltaAbsX() > body.deltaAbsY())
|
||||||
|
{
|
||||||
|
// Moving faster horizontally, check X axis first
|
||||||
|
minX = -1;
|
||||||
|
}
|
||||||
|
else if (body.deltaAbsX() < body.deltaAbsY())
|
||||||
|
{
|
||||||
|
// Moving faster vertically, check Y axis first
|
||||||
|
minY = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.deltaX() !== 0 && body.deltaY() !== 0 && faceHorizontal && faceVertical)
|
||||||
|
{
|
||||||
|
// We only need do this if both axes have colliding faces AND we're moving in both
|
||||||
|
// directions
|
||||||
|
minX = Math.min(Math.abs(body.position.x - tileRight), Math.abs(body.right - tileLeft));
|
||||||
|
minY = Math.min(Math.abs(body.position.y - tileBottom), Math.abs(body.bottom - tileTop));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minX < minY)
|
||||||
|
{
|
||||||
|
if (faceHorizontal)
|
||||||
|
{
|
||||||
|
ox = TileCheckX(body, tile, tilemapLayer);
|
||||||
|
|
||||||
|
// That's horizontal done, check if we still intersects? If not then we can return now
|
||||||
|
if (ox !== 0 && !TileIntersectsBody(tileWorldRect, body))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (faceVertical)
|
||||||
|
{
|
||||||
|
oy = TileCheckY(body, tile, tilemapLayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (faceVertical)
|
||||||
|
{
|
||||||
|
oy = TileCheckY(body, tile, tilemapLayer);
|
||||||
|
|
||||||
|
// That's vertical done, check if we still intersects? If not then we can return now
|
||||||
|
if (oy !== 0 && !TileIntersectsBody(tileWorldRect, body))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (faceHorizontal)
|
||||||
|
{
|
||||||
|
ox = TileCheckX(body, tile, tilemapLayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ox !== 0 || oy !== 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = SeparateTile;
|
63
src/physics/arcade/inc/tilemap/TileCheckX.js
Normal file
63
src/physics/arcade/inc/tilemap/TileCheckX.js
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
var TILE_BIAS = 16;
|
||||||
|
var ProcessTileSeparationX = require('./ProcessTileSeparationX');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the body against the given tile on the X axis.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @method Phaser.Physics.Arcade#tileCheckX
|
||||||
|
* @param {Phaser.Physics.Arcade.Body} body - The Body object to separate.
|
||||||
|
* @param {Phaser.Tile} tile - The tile to check.
|
||||||
|
* @param {Phaser.TilemapLayer} tilemapLayer - The tilemapLayer to collide against.
|
||||||
|
* @return {number} The amount of separation that occurred.
|
||||||
|
*/
|
||||||
|
var TileCheckX = function (body, tile, tilemapLayer)
|
||||||
|
{
|
||||||
|
var ox = 0;
|
||||||
|
var tileLeft = tilemapLayer.tileToWorldX(tile.x);
|
||||||
|
var tileWidth = tile.width * tilemapLayer.scaleX;
|
||||||
|
var tileRight = tileLeft + tileWidth;
|
||||||
|
|
||||||
|
if (body.deltaX() < 0 && !body.blocked.left && tile.collideRight && body.checkCollision.left)
|
||||||
|
{
|
||||||
|
// Body is moving LEFT
|
||||||
|
if (tile.faceRight && body.x < tileRight)
|
||||||
|
{
|
||||||
|
ox = body.x - tileRight;
|
||||||
|
|
||||||
|
if (ox < -TILE_BIAS)
|
||||||
|
{
|
||||||
|
ox = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (body.deltaX() > 0 && !body.blocked.right && tile.collideLeft && body.checkCollision.right)
|
||||||
|
{
|
||||||
|
// Body is moving RIGHT
|
||||||
|
if (tile.faceLeft && body.right > tileLeft)
|
||||||
|
{
|
||||||
|
ox = body.right - tileLeft;
|
||||||
|
|
||||||
|
if (ox > TILE_BIAS)
|
||||||
|
{
|
||||||
|
ox = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ox !== 0)
|
||||||
|
{
|
||||||
|
if (body.customSeparateX)
|
||||||
|
{
|
||||||
|
body.overlapX = ox;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ProcessTileSeparationX(body, ox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ox;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = TileCheckX;
|
63
src/physics/arcade/inc/tilemap/TileCheckY.js
Normal file
63
src/physics/arcade/inc/tilemap/TileCheckY.js
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
var TILE_BIAS = 16;
|
||||||
|
var ProcessTileSeparationY = require('./ProcessTileSeparationY');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the body against the given tile on the Y axis.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @method Phaser.Physics.Arcade#tileCheckY
|
||||||
|
* @param {Phaser.Physics.Arcade.Body} body - The Body object to separate.
|
||||||
|
* @param {Phaser.Tile} tile - The tile to check.
|
||||||
|
* @param {Phaser.TilemapLayer} tilemapLayer - The tilemapLayer to collide against.
|
||||||
|
* @return {number} The amount of separation that occurred.
|
||||||
|
*/
|
||||||
|
var TileCheckY = function (body, tile, tilemapLayer)
|
||||||
|
{
|
||||||
|
var oy = 0;
|
||||||
|
var tileTop = tilemapLayer.tileToWorldX(tile.y);
|
||||||
|
var tileHeight = tile.height * tilemapLayer.scaleY;
|
||||||
|
var tileBottom = tileTop + tileHeight;
|
||||||
|
|
||||||
|
if (body.deltaY() < 0 && !body.blocked.up && tile.collideDown && body.checkCollision.up)
|
||||||
|
{
|
||||||
|
// Body is moving UP
|
||||||
|
if (tile.faceBottom && body.y < tileBottom)
|
||||||
|
{
|
||||||
|
oy = body.y - tileBottom;
|
||||||
|
|
||||||
|
if (oy < -TILE_BIAS)
|
||||||
|
{
|
||||||
|
oy = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (body.deltaY() > 0 && !body.blocked.down && tile.collideUp && body.checkCollision.down)
|
||||||
|
{
|
||||||
|
// Body is moving DOWN
|
||||||
|
if (tile.faceTop && body.bottom > tileTop)
|
||||||
|
{
|
||||||
|
oy = body.bottom - tileTop;
|
||||||
|
|
||||||
|
if (oy > TILE_BIAS)
|
||||||
|
{
|
||||||
|
oy = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oy !== 0)
|
||||||
|
{
|
||||||
|
if (body.customSeparateY)
|
||||||
|
{
|
||||||
|
body.overlapY = oy;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ProcessTileSeparationY(body, oy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return oy;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = TileCheckY;
|
18
src/physics/arcade/inc/tilemap/TileIntersectsBody.js
Normal file
18
src/physics/arcade/inc/tilemap/TileIntersectsBody.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
var TileIntersectsBody = function (tileWorldRect, body)
|
||||||
|
{
|
||||||
|
if (body.isCircle)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return !(
|
||||||
|
body.right <= tileWorldRect.left ||
|
||||||
|
body.bottom <= tileWorldRect.top ||
|
||||||
|
body.position.x >= tileWorldRect.right ||
|
||||||
|
body.position.y >= tileWorldRect.bottom
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = TileIntersectsBody;
|
Loading…
Reference in a new issue