Added Body.tilePadding to help with small/fast moving bodies vs. tile collision.

This commit is contained in:
photonstorm 2014-03-13 23:15:32 +00:00
parent 5297497632
commit ec0b22268d
4 changed files with 59 additions and 133 deletions

View file

@ -27,15 +27,18 @@ function create() {
map.setCollisionBetween(1, 12); map.setCollisionBetween(1, 12);
layer.debug = true; // layer.debug = true;
sprite = game.add.sprite(260, 70, 'phaser'); sprite = game.add.sprite(260, 70, 'phaser');
game.physics.enable(sprite); game.physics.enable(sprite);
sprite.body.bounce.set(0.8);
sprite.body.tilePadding.set(32);
game.camera.follow(sprite); game.camera.follow(sprite);
// game.physics.arcade.gravity.y = 500; game.physics.arcade.gravity.y = 200;
cursors = game.input.keyboard.createCursorKeys(); cursors = game.input.keyboard.createCursorKeys();
@ -46,7 +49,7 @@ function update() {
game.physics.arcade.collide(sprite, layer); game.physics.arcade.collide(sprite, layer);
sprite.body.velocity.x = 0; sprite.body.velocity.x = 0;
sprite.body.velocity.y = 0; // sprite.body.velocity.y = 0;
if (cursors.up.isDown) if (cursors.up.isDown)
{ {
@ -76,6 +79,6 @@ function render() {
// game.debug.text(sprite.body.deltaX(), 400, 32); // game.debug.text(sprite.body.deltaX(), 400, 32);
// game.debug.text(sprite.body.deltaY(), 400, 64); // game.debug.text(sprite.body.deltaY(), 400, 64);
game.debug.body(sprite); // game.debug.body(sprite);
} }

View file

@ -18,6 +18,12 @@ var Phaser = Phaser || {
WEBGL: 2, WEBGL: 2,
HEADLESS: 3, HEADLESS: 3,
NONE: 0,
LEFT: 1,
RIGHT: 2,
UP: 3,
DOWN: 4,
SPRITE: 0, SPRITE: 0,
BUTTON: 1, BUTTON: 1,
IMAGE: 2, IMAGE: 2,

View file

@ -147,11 +147,6 @@ Phaser.Physics.Arcade.Body = function (sprite) {
*/ */
this.gravity = new Phaser.Point(0, 0); this.gravity = new Phaser.Point(0, 0);
/**
* @property {Phaser.Point} gravityScale - Gravity scaling factor. This is only applied to world gravity, not local gravity. If you want the body to ignore gravity, set this to zero. If you want to reverse gravity, set it to -1.
*/
this.gravityScale = new Phaser.Point(1, 1);
/** /**
* @property {Phaser.Point} bounce - The elasticitiy of the Body when colliding. bounce.x/y = 1 means full rebound, bounce.x/y = 0.5 means 50% rebound velocity. * @property {Phaser.Point} bounce - The elasticitiy of the Body when colliding. bounce.x/y = 1 means full rebound, bounce.x/y = 0.5 means 50% rebound velocity.
*/ */
@ -296,6 +291,13 @@ Phaser.Physics.Arcade.Body = function (sprite) {
*/ */
this.blocked = { up: false, down: false, left: false, right: false }; this.blocked = { up: false, down: false, left: false, right: false };
/**
* If this is an especially small or fast moving object then it can sometimes skip over tilemap collisions if it moves through a tile in a step.
* Set this padding value to add extra padding to its bounds. tilePadding.x applied to its width, y to its height.
* @property {Phaser.Point} tilePadding - Extra padding to be added to this sprites dimensions when checking for tile collision.
*/
this.tilePadding = new Phaser.Point();
}; };
Phaser.Physics.Arcade.Body.prototype = { Phaser.Physics.Arcade.Body.prototype = {
@ -403,8 +405,6 @@ Phaser.Physics.Arcade.Body.prototype = {
if (this.deltaX() !== 0 || this.deltaY() !== 0) if (this.deltaX() !== 0 || this.deltaY() !== 0)
{ {
// this.sprite.position.x = this.position.x;
// this.sprite.position.y = this.position.y;
this.sprite.x += this.deltaX(); this.sprite.x += this.deltaX();
this.sprite.y += this.deltaY(); this.sprite.y += this.deltaY();
this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight); this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight);

View file

@ -240,35 +240,12 @@ Phaser.Physics.Arcade.prototype = {
*/ */
updateMotion: function (body) { updateMotion: function (body) {
this._velocityDelta = this.computeVelocity(body.angularVelocity, body.angularAcceleration, body.angularDrag, body.maxAngular) - body.angularVelocity; this._velocityDelta = this.computeVelocity(0, body, body.angularVelocity, body.angularAcceleration, body.angularDrag, body.maxAngular) - body.angularVelocity;
body.angularVelocity += this._velocityDelta; body.angularVelocity += this._velocityDelta;
body.rotation += (body.angularVelocity * this.game.time.physicsElapsed); body.rotation += (body.angularVelocity * this.game.time.physicsElapsed);
// Apply gravity using the p2 style gravityScale body.velocity.x = this.computeVelocity(1, body, body.velocity.x, body.acceleration.x, body.drag.x, body.maxVelocity.x);
if (body.allowGravity) body.velocity.y = this.computeVelocity(2, body, body.velocity.y, body.acceleration.y, body.drag.y, body.maxVelocity.y);
{
if (body.gravity.x !== 0)
{
body.velocity.x += body.gravity.x * this.game.time.physicsElapsed;
}
else
{
body.velocity.x += this.gravity.x * this.game.time.physicsElapsed * body.gravityScale.x;
}
if (body.gravity.y !== 0)
{
body.velocity.y += body.gravity.y * this.game.time.physicsElapsed;
}
else
{
body.velocity.y += this.gravity.y * this.game.time.physicsElapsed * body.gravityScale.y;
}
}
// Apply velocity
body.velocity.x = this.computeVelocity(body.velocity.x, body.acceleration.x, body.drag.x, body.maxVelocity.x);
body.velocity.y = this.computeVelocity(body.velocity.y, body.acceleration.y, body.drag.y, body.maxVelocity.y);
}, },
@ -277,16 +254,27 @@ Phaser.Physics.Arcade.prototype = {
* Based on a function in Flixel by @ADAMATOMIC * Based on a function in Flixel by @ADAMATOMIC
* *
* @method Phaser.Physics.Arcade#computeVelocity * @method Phaser.Physics.Arcade#computeVelocity
* @param {number} axis - 0 for nothing, 1 for horizontal, 2 for vertical.
* @param {Phaser.Physics.Arcade.Body} body - The Body object to be updated.
* @param {number} velocity - Any component of velocity (e.g. 20). * @param {number} velocity - Any component of velocity (e.g. 20).
* @param {number} acceleration - Rate at which the velocity is changing. * @param {number} acceleration - Rate at which the velocity is changing.
* @param {number} drag - Really kind of a deceleration, this is how much the velocity changes if Acceleration is not set. * @param {number} drag - Really kind of a deceleration, this is how much the velocity changes if Acceleration is not set.
* @param {number} [max=10000] - An absolute value cap for the velocity. * @param {number} [max=10000] - An absolute value cap for the velocity.
* @return {number} The altered Velocity value. * @return {number} The altered Velocity value.
*/ */
computeVelocity: function (velocity, acceleration, drag, max) { computeVelocity: function (axis, body, velocity, acceleration, drag, max) {
max = max || 10000; max = max || 10000;
if (axis == 1 && body.allowGravity)
{
velocity += (this.gravity.x + body.gravity.x) * this.game.time.physicsElapsed;
}
else if (axis == 2 && body.allowGravity)
{
velocity += (this.gravity.y + body.gravity.y) * this.game.time.physicsElapsed;
}
if (acceleration) if (acceleration)
{ {
velocity += acceleration * this.game.time.physicsElapsed; velocity += acceleration * this.game.time.physicsElapsed;
@ -606,8 +594,12 @@ Phaser.Physics.Arcade.prototype = {
*/ */
collideSpriteVsTilemapLayer: function (sprite, tilemapLayer, collideCallback, processCallback, callbackContext) { collideSpriteVsTilemapLayer: function (sprite, tilemapLayer, collideCallback, processCallback, callbackContext) {
// this._mapData = tilemapLayer.getIntersectingTiles(sprite.body.position.x, sprite.body.position.y, sprite.body.width, sprite.body.height, sprite.body.right, sprite.body.bottom); this._mapData = tilemapLayer.getTiles(
this._mapData = tilemapLayer.getTiles(sprite.body.position.x, sprite.body.position.y, sprite.body.width, sprite.body.height, false, true); sprite.body.position.x - sprite.body.tilePadding.x,
sprite.body.position.y - sprite.body.tilePadding.y,
sprite.body.width + sprite.body.tilePadding.x,
sprite.body.height + sprite.body.tilePadding.y,
false, true);
if (this._mapData.length === 0) if (this._mapData.length === 0)
{ {
@ -616,9 +608,6 @@ Phaser.Physics.Arcade.prototype = {
for (var i = 0; i < this._mapData.length; i++) for (var i = 0; i < this._mapData.length; i++)
{ {
// console.log('-------------------------------------- tile', this._mapData[i].faceLeft, this._mapData[i].faceRight, this._mapData[i].faceTop, this._mapData[i].faceBottom);
// console.log('-------------------------------------- tile', i, 'of', this._mapData.length, 'xy', this._mapData[i].x, this._mapData[i].y);
if (this.separateTile(i, sprite.body, this._mapData[i])) if (this.separateTile(i, sprite.body, this._mapData[i]))
{ {
// They collided, is there a custom process callback? // They collided, is there a custom process callback?
@ -945,86 +934,6 @@ Phaser.Physics.Arcade.prototype = {
}, },
BUSTEDseparateTile: function (i, body, tile) {
// we re-check for collision in case body was separated in a previous step
if (i > 0 && !tile.intersects(body.position.x, body.position.y, body.right, body.bottom))
{
// no collision so bail out (separted in a previous step)
console.log('no collision so bail out (separted in a previous step');
return false;
}
console.log('body intersecting tile');
console.log('x', body.position.x, 'y', body.position.y, 'r', body.right, 'b', body.bottom, 'wh', body.width, body.height);
console.log('x', tile.x, 'y', tile.y, 'r', tile.right, 'b', tile.bottom);
if (body.newVelocity.x && (tile.faceLeft || tile.faceRight))
{
var px = 0;
var tx = 0;
if (body.newVelocity.x > 0 && tile.faceLeft)
{
px = body.width;
}
else if (body.newVelocity.x < 0 && tile.faceRight)
{
tx = tile.width;
}
body.position.x = tile.worldX - px + tx;
body.velocity.x = 0; // rebound check
// body.newVelocity.x = 0; // rebound check
}
// Vertical only if still colliding
// if (tile.intersects(body.position.x, body.position.y, body.right, body.bottom))
// if (body.newVelocity.y && tile.intersects(body.position.x, body.position.y, body.right, body.bottom))
if (body.newVelocity.y && (tile.faceTop || tile.faceBottom))
{
var py = 0;
var ty = 0;
if (body.newVelocity.y > 0 && tile.faceBottom)
{
py = body.height;
}
else if (body.newVelocity.y < 0 && tile.faceTop)
{
ty = tile.height;
}
// console.log('cy', body.newVelocity.y, py, ty);
body.position.y = tile.worldY - py + ty;
body.velocity.y = 0; // rebound check
// body.newVelocity.y = 0; // rebound check
}
// var pxOffsetX = (body.newVelocity.x > 0 ? body.width : 0);
// var tileOffsetX = (body.newVelocity.x < 0 ? tile.width : 0);
// var pxOffsetY = (body.newVelocity.y > 0 ? body.height : 0);
// var tileOffsetY = (body.newVelocity.y < 0 ? tile.height : 0);
// Assume fully solid for now
// body.result.x = true;
// body.result.tile = tile;
// body.result.px = tile.x - pxOffsetX + tileOffsetX;
// body.position.x = tile.x - pxOffsetX + tileOffsetX;
// res.pos.y = tileY * this.tilesize - pxOffsetY + tileOffsetY;
// console.log('nv', body.newVelocity.x, 'tile.xy', tile.x, tile.y, 'p', pxOffsetX, 't', tileOffsetX, 'body xy', body.position.x, body.position.y);
},
/** /**
* The core separation function to separate a physics body and a tile. * The core separation function to separate a physics body and a tile.
* @method Phaser.Physics.Arcade#separateTile * @method Phaser.Physics.Arcade#separateTile
@ -1080,16 +989,6 @@ Phaser.Physics.Arcade.prototype = {
minY = Math.min(Math.abs(body.position.y - tile.bottom), Math.abs(body.bottom - tile.top)); minY = Math.min(Math.abs(body.position.y - tile.bottom), Math.abs(body.bottom - tile.top));
// console.log('checking faces', minX, minY); // console.log('checking faces', minX, minY);
// var distLeft = Math.abs(body.position.x - tile.right);
// var distRight = Math.abs(body.right - tile.left);
// var distTop = Math.abs(body.position.y - tile.bottom);
// var distBottom = Math.abs(body.bottom - tile.top);
// minX = Math.min(distLeft, distRight);
// minY = Math.min(distTop, distBottom);
// console.log('dist left', distLeft, 'right', distRight, 'top', distTop, 'bottom', distBottom, 'minX', minX, 'minY', minY);
// console.log('tile lr', tile.left, tile.right, 'tb', tile.top, tile.bottom);
// console.log('body lr', body.x, body.right, 'tb', body.y, body.bottom);
} }
if (minX < minY) if (minX < minY)
@ -1133,6 +1032,15 @@ Phaser.Physics.Arcade.prototype = {
}, },
/**
* Check the body against the given tile on the X axis.
*
* @method Phaser.Physics.Arcade#tileCheckX
* @protected
* @param {Phaser.Physics.Arcade.Body} body - The Body object to separate.
* @param {Phaser.Tile} tile - The tile to check.
* @returns {number} The amount of separation that occured.
*/
tileCheckX: function (body, tile) { tileCheckX: function (body, tile) {
var ox = 0; var ox = 0;
@ -1173,6 +1081,15 @@ Phaser.Physics.Arcade.prototype = {
}, },
/**
* Check the body against the given tile on the Y axis.
*
* @method Phaser.Physics.Arcade#tileCheckY
* @protected
* @param {Phaser.Physics.Arcade.Body} body - The Body object to separate.
* @param {Phaser.Tile} tile - The tile to check.
* @returns {number} The amount of separation that occured.
*/
tileCheckY: function (body, tile) { tileCheckY: function (body, tile) {
var oy = 0; var oy = 0;