mirror of
https://github.com/photonstorm/phaser
synced 2024-11-24 21:53:59 +00:00
358 lines
10 KiB
JavaScript
358 lines
10 KiB
JavaScript
/**
|
|
* @author Richard Davey <rich@photonstorm.com>
|
|
* @copyright 2020 Photon Storm Ltd.
|
|
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
|
*/
|
|
|
|
var Class = require('../../utils/Class');
|
|
var DefaultDefs = require('./DefaultDefs');
|
|
|
|
/**
|
|
* @classdesc
|
|
* [description]
|
|
*
|
|
* @class CollisionMap
|
|
* @memberof Phaser.Physics.Impact
|
|
* @constructor
|
|
* @since 3.0.0
|
|
*
|
|
* @param {integer} [tilesize=32] - [description]
|
|
* @param {array} [data] - [description]
|
|
*/
|
|
var CollisionMap = new Class({
|
|
|
|
initialize:
|
|
|
|
function CollisionMap (tilesize, data)
|
|
{
|
|
if (tilesize === undefined) { tilesize = 32; }
|
|
|
|
/**
|
|
* [description]
|
|
*
|
|
* @name Phaser.Physics.Impact.CollisionMap#tilesize
|
|
* @type {integer}
|
|
* @default 32
|
|
* @since 3.0.0
|
|
*/
|
|
this.tilesize = tilesize;
|
|
|
|
/**
|
|
* [description]
|
|
*
|
|
* @name Phaser.Physics.Impact.CollisionMap#data
|
|
* @type {array}
|
|
* @since 3.0.0
|
|
*/
|
|
this.data = (Array.isArray(data)) ? data : [];
|
|
|
|
/**
|
|
* [description]
|
|
*
|
|
* @name Phaser.Physics.Impact.CollisionMap#width
|
|
* @type {number}
|
|
* @since 3.0.0
|
|
*/
|
|
this.width = (Array.isArray(data)) ? data[0].length : 0;
|
|
|
|
/**
|
|
* [description]
|
|
*
|
|
* @name Phaser.Physics.Impact.CollisionMap#height
|
|
* @type {number}
|
|
* @since 3.0.0
|
|
*/
|
|
this.height = (Array.isArray(data)) ? data.length : 0;
|
|
|
|
/**
|
|
* [description]
|
|
*
|
|
* @name Phaser.Physics.Impact.CollisionMap#lastSlope
|
|
* @type {integer}
|
|
* @default 55
|
|
* @since 3.0.0
|
|
*/
|
|
this.lastSlope = 55;
|
|
|
|
/**
|
|
* [description]
|
|
*
|
|
* @name Phaser.Physics.Impact.CollisionMap#tiledef
|
|
* @type {object}
|
|
* @since 3.0.0
|
|
*/
|
|
this.tiledef = DefaultDefs;
|
|
},
|
|
|
|
/**
|
|
* [description]
|
|
*
|
|
* @method Phaser.Physics.Impact.CollisionMap#trace
|
|
* @since 3.0.0
|
|
*
|
|
* @param {number} x - [description]
|
|
* @param {number} y - [description]
|
|
* @param {number} vx - [description]
|
|
* @param {number} vy - [description]
|
|
* @param {number} objectWidth - [description]
|
|
* @param {number} objectHeight - [description]
|
|
*
|
|
* @return {boolean} [description]
|
|
*/
|
|
trace: function (x, y, vx, vy, objectWidth, objectHeight)
|
|
{
|
|
// Set up the trace-result
|
|
var res = {
|
|
collision: { x: false, y: false, slope: false },
|
|
pos: { x: x + vx, y: y + vy },
|
|
tile: { x: 0, y: 0 }
|
|
};
|
|
|
|
if (!this.data)
|
|
{
|
|
return res;
|
|
}
|
|
|
|
var steps = Math.ceil(Math.max(Math.abs(vx), Math.abs(vy)) / this.tilesize);
|
|
|
|
if (steps > 1)
|
|
{
|
|
var sx = vx / steps;
|
|
var sy = vy / steps;
|
|
|
|
for (var i = 0; i < steps && (sx || sy); i++)
|
|
{
|
|
this.step(res, x, y, sx, sy, objectWidth, objectHeight, vx, vy, i);
|
|
|
|
x = res.pos.x;
|
|
y = res.pos.y;
|
|
|
|
if (res.collision.x)
|
|
{
|
|
sx = 0;
|
|
vx = 0;
|
|
}
|
|
|
|
if (res.collision.y)
|
|
{
|
|
sy = 0;
|
|
vy = 0;
|
|
}
|
|
|
|
if (res.collision.slope)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this.step(res, x, y, vx, vy, objectWidth, objectHeight, vx, vy, 0);
|
|
}
|
|
|
|
return res;
|
|
},
|
|
|
|
/**
|
|
* [description]
|
|
*
|
|
* @method Phaser.Physics.Impact.CollisionMap#step
|
|
* @since 3.0.0
|
|
*
|
|
* @param {object} res - [description]
|
|
* @param {number} x - [description]
|
|
* @param {number} y - [description]
|
|
* @param {number} vx - [description]
|
|
* @param {number} vy - [description]
|
|
* @param {number} width - [description]
|
|
* @param {number} height - [description]
|
|
* @param {number} rvx - [description]
|
|
* @param {number} rvy - [description]
|
|
* @param {number} step - [description]
|
|
*/
|
|
step: function (res, x, y, vx, vy, width, height, rvx, rvy, step)
|
|
{
|
|
var t = 0;
|
|
var tileX;
|
|
var tileY;
|
|
var tilesize = this.tilesize;
|
|
var mapWidth = this.width;
|
|
var mapHeight = this.height;
|
|
|
|
// Horizontal
|
|
if (vx)
|
|
{
|
|
var pxOffsetX = (vx > 0 ? width : 0);
|
|
var tileOffsetX = (vx < 0 ? tilesize : 0);
|
|
|
|
var firstTileY = Math.max(Math.floor(y / tilesize), 0);
|
|
var lastTileY = Math.min(Math.ceil((y + height) / tilesize), mapHeight);
|
|
|
|
tileX = Math.floor((res.pos.x + pxOffsetX) / tilesize);
|
|
|
|
var prevTileX = Math.floor((x + pxOffsetX) / tilesize);
|
|
|
|
if (step > 0 || tileX === prevTileX || prevTileX < 0 || prevTileX >= mapWidth)
|
|
{
|
|
prevTileX = -1;
|
|
}
|
|
|
|
if (tileX >= 0 && tileX < mapWidth)
|
|
{
|
|
for (tileY = firstTileY; tileY < lastTileY; tileY++)
|
|
{
|
|
if (prevTileX !== -1)
|
|
{
|
|
t = this.data[tileY][prevTileX];
|
|
|
|
if (t > 1 && t <= this.lastSlope && this.checkDef(res, t, x, y, rvx, rvy, width, height, prevTileX, tileY))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
t = this.data[tileY][tileX];
|
|
|
|
if (t === 1 || t > this.lastSlope || (t > 1 && this.checkDef(res, t, x, y, rvx, rvy, width, height, tileX, tileY)))
|
|
{
|
|
if (t > 1 && t <= this.lastSlope && res.collision.slope)
|
|
{
|
|
break;
|
|
}
|
|
|
|
res.collision.x = true;
|
|
res.tile.x = t;
|
|
res.pos.x = (tileX * tilesize) - pxOffsetX + tileOffsetX;
|
|
x = res.pos.x;
|
|
rvx = 0;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Vertical
|
|
if (vy)
|
|
{
|
|
var pxOffsetY = (vy > 0 ? height : 0);
|
|
var tileOffsetY = (vy < 0 ? tilesize : 0);
|
|
|
|
var firstTileX = Math.max(Math.floor(res.pos.x / tilesize), 0);
|
|
var lastTileX = Math.min(Math.ceil((res.pos.x + width) / tilesize), mapWidth);
|
|
|
|
tileY = Math.floor((res.pos.y + pxOffsetY) / tilesize);
|
|
|
|
var prevTileY = Math.floor((y + pxOffsetY) / tilesize);
|
|
|
|
if (step > 0 || tileY === prevTileY || prevTileY < 0 || prevTileY >= mapHeight)
|
|
{
|
|
prevTileY = -1;
|
|
}
|
|
|
|
if (tileY >= 0 && tileY < mapHeight)
|
|
{
|
|
for (tileX = firstTileX; tileX < lastTileX; tileX++)
|
|
{
|
|
if (prevTileY !== -1)
|
|
{
|
|
t = this.data[prevTileY][tileX];
|
|
|
|
if (t > 1 && t <= this.lastSlope && this.checkDef(res, t, x, y, rvx, rvy, width, height, tileX, prevTileY))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
t = this.data[tileY][tileX];
|
|
|
|
if (t === 1 || t > this.lastSlope || (t > 1 && this.checkDef(res, t, x, y, rvx, rvy, width, height, tileX, tileY)))
|
|
{
|
|
if (t > 1 && t <= this.lastSlope && res.collision.slope)
|
|
{
|
|
break;
|
|
}
|
|
|
|
res.collision.y = true;
|
|
res.tile.y = t;
|
|
res.pos.y = tileY * tilesize - pxOffsetY + tileOffsetY;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* [description]
|
|
*
|
|
* @method Phaser.Physics.Impact.CollisionMap#checkDef
|
|
* @since 3.0.0
|
|
*
|
|
* @param {object} res - [description]
|
|
* @param {number} t - [description]
|
|
* @param {number} x - [description]
|
|
* @param {number} y - [description]
|
|
* @param {number} vx - [description]
|
|
* @param {number} vy - [description]
|
|
* @param {number} width - [description]
|
|
* @param {number} height - [description]
|
|
* @param {number} tileX - [description]
|
|
* @param {number} tileY - [description]
|
|
*
|
|
* @return {boolean} [description]
|
|
*/
|
|
checkDef: function (res, t, x, y, vx, vy, width, height, tileX, tileY)
|
|
{
|
|
var def = this.tiledef[t];
|
|
|
|
if (!def)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var tilesize = this.tilesize;
|
|
|
|
var lx = (tileX + def[0]) * tilesize;
|
|
var ly = (tileY + def[1]) * tilesize;
|
|
var lvx = (def[2] - def[0]) * tilesize;
|
|
var lvy = (def[3] - def[1]) * tilesize;
|
|
var solid = def[4];
|
|
|
|
var tx = x + vx + (lvy < 0 ? width : 0) - lx;
|
|
var ty = y + vy + (lvx > 0 ? height : 0) - ly;
|
|
|
|
if (lvx * ty - lvy * tx > 0)
|
|
{
|
|
if (vx * -lvy + vy * lvx < 0)
|
|
{
|
|
return solid;
|
|
}
|
|
|
|
var length = Math.sqrt(lvx * lvx + lvy * lvy);
|
|
var nx = lvy / length;
|
|
var ny = -lvx / length;
|
|
|
|
var proj = tx * nx + ty * ny;
|
|
var px = nx * proj;
|
|
var py = ny * proj;
|
|
|
|
if (px * px + py * py >= vx * vx + vy * vy)
|
|
{
|
|
return solid || (lvx * (ty - vy) - lvy * (tx - vx) < 0.5);
|
|
}
|
|
|
|
res.pos.x = x + vx - px;
|
|
res.pos.y = y + vy - py;
|
|
res.collision.slope = { x: lvx, y: lvy, nx: nx, ny: ny };
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
});
|
|
|
|
module.exports = CollisionMap;
|