From 52974976324a848864c07fcc689a45668db6db8f Mon Sep 17 00:00:00 2001 From: photonstorm Date: Thu, 13 Mar 2014 22:49:08 +0000 Subject: [PATCH] Tilemap collision finally getting closer. --- examples/wip/tilemap new 1.js | 18 +-- src/physics/arcade/Body.js | 4 +- src/physics/arcade/World.js | 204 +++++++++++++++++++++++++--------- src/tilemap/Tile.js | 30 +++++ src/tilemap/TilemapLayer.js | 9 +- 5 files changed, 201 insertions(+), 64 deletions(-) diff --git a/examples/wip/tilemap new 1.js b/examples/wip/tilemap new 1.js index d630b9c9e..e3e7e3cff 100644 --- a/examples/wip/tilemap new 1.js +++ b/examples/wip/tilemap new 1.js @@ -36,7 +36,6 @@ function create() { game.camera.follow(sprite); // game.physics.arcade.gravity.y = 500; - // sprite.body.velocity.x = 100; cursors = game.input.keyboard.createCursorKeys(); @@ -51,27 +50,32 @@ function update() { if (cursors.up.isDown) { - sprite.body.velocity.y = -100; + sprite.body.velocity.y = -200; } else if (cursors.down.isDown) { - sprite.body.velocity.y = 100; + sprite.body.velocity.y = 200; } if (cursors.left.isDown) { - sprite.body.velocity.x = -100; + sprite.body.velocity.x = -200; } else if (cursors.right.isDown) { - sprite.body.velocity.x = 100; + sprite.body.velocity.x = 200; } } function render() { - game.debug.text(sprite.body.velocity.x, 32, 32); - game.debug.text(sprite.body.velocity.y, 64, 32); + // game.debug.text(sprite.body.deltaAbsX(), 32, 32); + // game.debug.text(sprite.body.deltaAbsY(), 32, 64); + + // game.debug.text(sprite.body.deltaX(), 400, 32); + // game.debug.text(sprite.body.deltaY(), 400, 64); + + game.debug.body(sprite); } diff --git a/src/physics/arcade/Body.js b/src/physics/arcade/Body.js index f8f7c8ecb..8f6fae67d 100644 --- a/src/physics/arcade/Body.js +++ b/src/physics/arcade/Body.js @@ -632,12 +632,12 @@ Phaser.Physics.Arcade.Body.render = function (context, body, filled, color) { if (filled) { context.fillStyle = color; - context.fillRect(body.x - body.game.camera.x, body.y - body.game.camera.y, body.width, body.height); + context.fillRect(body.position.x - body.game.camera.x, body.position.y - body.game.camera.y, body.width, body.height); } else { context.strokeStyle = color; - context.strokeRect(body.x - body.game.camera.x, body.y - body.game.camera.y, body.width, body.height); + context.strokeRect(body.position.x - body.game.camera.x, body.position.y - body.game.camera.y, body.width, body.height); } } diff --git a/src/physics/arcade/World.js b/src/physics/arcade/World.js index 313068e9a..9bbc00ed6 100644 --- a/src/physics/arcade/World.js +++ b/src/physics/arcade/World.js @@ -606,7 +606,8 @@ Phaser.Physics.Arcade.prototype = { */ 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.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(sprite.body.position.x, sprite.body.position.y, sprite.body.width, sprite.body.height, false, true); if (this._mapData.length === 0) { @@ -616,6 +617,8 @@ Phaser.Physics.Arcade.prototype = { 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])) { // They collided, is there a custom process callback? @@ -743,7 +746,9 @@ Phaser.Physics.Arcade.prototype = { } else { + body1.touching.none = false; body1.touching.right = true; + body2.touching.none = false; body2.touching.left = true; } } @@ -758,7 +763,9 @@ Phaser.Physics.Arcade.prototype = { } else { + body1.touching.none = false; body1.touching.left = true; + body2.touching.none = false; body2.touching.right = true; } } @@ -852,7 +859,9 @@ Phaser.Physics.Arcade.prototype = { } else { + body1.touching.none = false; body1.touching.down = true; + body2.touching.none = false; body2.touching.up = true; } } @@ -867,7 +876,9 @@ Phaser.Physics.Arcade.prototype = { } else { + body1.touching.none = false; body1.touching.up = true; + body2.touching.none = false; body2.touching.down = true; } } @@ -1023,8 +1034,8 @@ Phaser.Physics.Arcade.prototype = { */ separateTile: 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)) + // We re-check for collision in case body was separated in a previous step + if (!tile.intersects(body.position.x, body.position.y, body.right, body.bottom)) { // no collision so bail out (separted in a previous step) return false; @@ -1048,60 +1059,73 @@ Phaser.Physics.Arcade.prototype = { var ox = 0; var oy = 0; + var minX = 0; + var minY = 1; - if (tile.faceLeft || tile.faceRight) + if (body.deltaAbsX() > body.deltaAbsY()) { - if (body.deltaX() < 0 && !body.blocked.left && tile.collideRight && body.checkCollision.left) - { - // Body is moving LEFT - if (tile.faceRight && body.x < tile.right) - { - ox = body.x - tile.right; - } - } - else if (body.deltaX() > 0 && !body.blocked.right && tile.collideLeft && body.checkCollision.right) - { - // Body is moving RIGHT - if (tile.faceLeft && body.right > tile.left) - { - ox = body.right - tile.left; - } - } - - if (ox !== 0) - { - this.processTileSeparationX(body, ox); - } - - // That's horizontal done, check if we still intersects? If not then we can return now - if (!tile.intersects(body.position.x, body.position.y, body.right, body.bottom)) - { - return (ox !== 0); - } + // 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 (tile.faceTop || tile.faceBottom) + if (body.deltaX() !== 0 && body.deltaY() !== 0 && (tile.faceLeft || tile.faceRight) && (tile.faceTop || tile.faceBottom)) { - if (body.deltaY() < 0 && !body.blocked.up && tile.collideDown && body.checkCollision.up) - { - // Body is moving UP - if (tile.faceBottom && body.y < tile.bottom) - { - oy = body.y - tile.bottom; - } - } - else if (body.deltaY() > 0 && !body.blocked.down && tile.collideUp && body.checkCollision.down) - { - // Body is moving DOWN - if (tile.faceTop && body.bottom > tile.top) - { - oy = body.bottom - tile.top; - } - } + // We only need do this if both axis have checking faces AND we're moving in both directions + minX = Math.min(Math.abs(body.position.x - tile.right), Math.abs(body.right - tile.left)); + minY = Math.min(Math.abs(body.position.y - tile.bottom), Math.abs(body.bottom - tile.top)); - if (oy !== 0) + // 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 (tile.faceLeft || tile.faceRight) { - this.processTileSeparationY(body, oy); + ox = this.tileCheckX(body, tile); + + // That's horizontal done, check if we still intersects? If not then we can return now + if (ox !== 0 && !tile.intersects(body.position.x, body.position.y, body.right, body.bottom)) + { + return true; + } + } + + if (tile.faceTop || tile.faceBottom) + { + oy = this.tileCheckY(body, tile); + } + } + else + { + if (tile.faceTop || tile.faceBottom) + { + oy = this.tileCheckY(body, tile); + + // That's vertical done, check if we still intersects? If not then we can return now + if (oy !== 0 && !tile.intersects(body.position.x, body.position.y, body.right, body.bottom)) + { + return true; + } + } + + if (tile.faceLeft || tile.faceRight) + { + ox = this.tileCheckX(body, tile); } } @@ -1109,6 +1133,86 @@ Phaser.Physics.Arcade.prototype = { }, + tileCheckX: function (body, tile) { + + var ox = 0; + + if (body.deltaX() < 0 && !body.blocked.left && tile.collideRight && body.checkCollision.left) + { + // Body is moving LEFT + if (tile.faceRight && body.x < tile.right) + { + ox = body.x - tile.right; + + if (ox < -this.OVERLAP_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 > tile.left) + { + ox = body.right - tile.left; + + if (ox > this.OVERLAP_BIAS) + { + ox = 0; + } + } + } + + if (ox !== 0) + { + this.processTileSeparationX(body, ox); + } + + return ox; + + }, + + tileCheckY: function (body, tile) { + + var oy = 0; + + if (body.deltaY() < 0 && !body.blocked.up && tile.collideDown && body.checkCollision.up) + { + // Body is moving UP + if (tile.faceBottom && body.y < tile.bottom) + { + oy = body.y - tile.bottom; + + if (oy < -this.OVERLAP_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 > tile.top) + { + oy = body.bottom - tile.top; + + if (oy > this.OVERLAP_BIAS) + { + oy = 0; + } + } + } + + if (oy !== 0) + { + this.processTileSeparationY(body, oy); + } + + return oy; + + }, + /** * Internal function to process the separation of a physics body from a tile. * @method Phaser.Physics.Arcade#processTileSeparationX diff --git a/src/tilemap/Tile.js b/src/tilemap/Tile.js index b21549ae6..e24e89eff 100644 --- a/src/tilemap/Tile.js +++ b/src/tilemap/Tile.js @@ -244,6 +244,36 @@ Phaser.Tile.prototype = { }, + /** + * Is this tile interesting? + * + * @method Phaser.Tile#isInteresting + * @param {boolean} collides - If true will check any collides value. + * @param {boolean} faces - If true will check any face value. + * @return {boolean} True if the Tile is interesting, otherwise false. + */ + isInteresting: function (collides, faces) { + + if (collides && faces) + { + // Does this tile EITHER collide OR have an interesting face? + return (this.collideLeft || this.collideRight || this.collideUp || this.collideDown || this.faceTop || this.faceBottom || this.faceLeft || this.faceRight); + } + else if (collides) + { + // Does this tile collide? + return (this.collideLeft || this.collideRight || this.collideUp || this.collideDown); + } + else if (faces) + { + // Does this tile have an interesting face? + return (this.faceTop || this.faceBottom || this.faceLeft || this.faceRight); + } + + return false; + + }, + /** * Copies the tile data and properties from the given tile to this tile. * diff --git a/src/tilemap/TilemapLayer.js b/src/tilemap/TilemapLayer.js index fbe5937c6..582d17212 100644 --- a/src/tilemap/TilemapLayer.js +++ b/src/tilemap/TilemapLayer.js @@ -541,12 +541,14 @@ Phaser.TilemapLayer.prototype.getTilesX = function (x, y, width, height, collide * @param {number} width - Width of the area to get. * @param {number} height - Height of the area to get. * @param {boolean} [collides=false] - If true only return tiles that collide on one or more faces. +* @param {boolean} [interestingFace=false] - If true only return tiles that have interesting faces. * @return {array} Array with tiles informations (each contains x, y, and the tile). */ -Phaser.TilemapLayer.prototype.getTiles = function (x, y, width, height, collides) { +Phaser.TilemapLayer.prototype.getTiles = function (x, y, width, height, collides, interestingFace) { // Should we only get tiles that have at least one of their collision flags set? (true = yes, false = no just get them all) if (typeof collides === 'undefined') { collides = false; } + if (typeof interestingFace === 'undefined') { interestingFace = false; } // adjust the x,y coordinates for scrollFactor x = this._fixX(x); @@ -577,7 +579,7 @@ Phaser.TilemapLayer.prototype.getTiles = function (x, y, width, height, collides { if (this.layer.data[wy] && this.layer.data[wy][wx]) { - if (collides === false || (collides && this.layer.data[wy][wx].canCollide)) + if ((!collides && !interestingFace) || this.layer.data[wy][wx].isInteresting(collides, interestingFace)) { this._results.push(this.layer.data[wy][wx]); } @@ -585,9 +587,6 @@ Phaser.TilemapLayer.prototype.getTiles = function (x, y, width, height, collides } } - // DEBUG ONLY - REMOVE - this.layer.dirty = true; - return this._results; }