phaser/src/physics/impact/CollisionMap.js

247 lines
7.2 KiB
JavaScript
Raw Normal View History

2017-06-22 01:40:10 +00:00
// Phaser.Physics.Impact.CollisionMap
var Class = require('../../utils/Class');
var DefaultDefs = require('./DefaultDefs');
var CollisionMap = new Class({
initialize:
function CollisionMap (tilesize, data)
{
if (tilesize === undefined) { tilesize = 32; }
2017-06-22 01:40:10 +00:00
this.tilesize = tilesize;
this.data = (Array.isArray(data)) ? data : [];
2017-06-22 01:40:10 +00:00
this.width = (Array.isArray(data)) ? data[0].length : 0;
this.height = (Array.isArray(data)) ? data.length : 0;
this.lastSlope = 55;
2017-06-22 01:40:10 +00:00
this.tiledef = DefaultDefs;
},
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 },
2017-06-22 01:40:10 +00:00
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;
},
step: function (res, x, y, vx, vy, width, height, rvx, rvy, step)
{
var t = 0;
2017-08-18 16:01:51 +00:00
var tileX;
var tileY;
2017-06-22 01:40:10 +00:00
var tilesize = this.tilesize;
2017-06-22 03:56:50 +00:00
var mapWidth = this.width;
var mapHeight = this.height;
2017-06-22 01:40:10 +00:00
// Horizontal
if (vx)
{
var pxOffsetX = (vx > 0 ? width : 0);
var tileOffsetX = (vx < 0 ? tilesize : 0);
2017-06-22 01:40:10 +00:00
var firstTileY = Math.max(Math.floor(y / tilesize), 0);
2017-06-22 03:56:50 +00:00
var lastTileY = Math.min(Math.ceil((y + height) / tilesize), mapHeight);
2017-08-18 16:01:51 +00:00
tileX = Math.floor((res.pos.x + pxOffsetX) / tilesize);
2017-06-22 01:40:10 +00:00
var prevTileX = Math.floor((x + pxOffsetX) / tilesize);
2017-06-22 03:56:50 +00:00
if (step > 0 || tileX === prevTileX || prevTileX < 0 || prevTileX >= mapWidth)
2017-06-22 01:40:10 +00:00
{
prevTileX = -1;
}
2017-08-18 16:01:51 +00:00
2017-06-22 03:56:50 +00:00
if (tileX >= 0 && tileX < mapWidth)
2017-06-22 01:40:10 +00:00
{
2017-08-18 16:01:51 +00:00
for (tileY = firstTileY; tileY < lastTileY; tileY++)
2017-06-22 01:40:10 +00:00
{
if (prevTileX !== -1)
2017-06-22 01:40:10 +00:00
{
t = this.data[tileY][prevTileX];
if (t > 1 && t <= this.lastSlope && this.checkDef(res, t, x, y, rvx, rvy, width, height, prevTileX, tileY))
2017-06-22 01:40:10 +00:00
{
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)))
2017-06-22 01:40:10 +00:00
{
if (t > 1 && t <= this.lastSlope && res.collision.slope)
2017-06-22 01:40:10 +00:00
{
break;
}
res.collision.x = true;
res.tile.x = t;
2017-06-23 17:13:38 +00:00
res.pos.x = (tileX * tilesize) - pxOffsetX + tileOffsetX;
x = res.pos.x;
rvx = 0;
2017-06-22 01:40:10 +00:00
break;
}
}
}
}
// Vertical
if (vy)
{
var pxOffsetY = (vy > 0 ? height : 0);
var tileOffsetY = (vy < 0 ? tilesize : 0);
2017-06-22 01:40:10 +00:00
var firstTileX = Math.max(Math.floor(res.pos.x / tilesize), 0);
2017-06-22 03:56:50 +00:00
var lastTileX = Math.min(Math.ceil((res.pos.x + width) / tilesize), mapWidth);
2017-08-18 16:01:51 +00:00
tileY = Math.floor((res.pos.y + pxOffsetY) / tilesize);
2017-06-22 01:40:10 +00:00
var prevTileY = Math.floor((y + pxOffsetY) / tilesize);
2017-06-22 03:56:50 +00:00
if (step > 0 || tileY === prevTileY || prevTileY < 0 || prevTileY >= mapHeight)
2017-06-22 01:40:10 +00:00
{
prevTileY = -1;
}
2017-06-22 03:56:50 +00:00
if (tileY >= 0 && tileY < mapHeight)
2017-06-22 01:40:10 +00:00
{
2017-08-18 16:01:51 +00:00
for (tileX = firstTileX; tileX < lastTileX; tileX++)
2017-06-22 01:40:10 +00:00
{
if (prevTileY !== -1)
2017-06-22 01:40:10 +00:00
{
t = this.data[prevTileY][tileX];
if (t > 1 && t <= this.lastSlope && this.checkDef(res, t, x, y, rvx, rvy, width, height, tileX, prevTileY))
2017-06-22 01:40:10 +00:00
{
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)))
2017-06-22 01:40:10 +00:00
{
if (t > 1 && t <= this.lastSlope && res.collision.slope)
2017-06-22 01:40:10 +00:00
{
break;
}
res.collision.y = true;
res.tile.y = t;
res.pos.y = tileY * tilesize - pxOffsetY + tileOffsetY;
break;
}
}
}
}
},
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);
2017-06-22 01:40:10 +00:00
}
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;