mirror of
https://github.com/photonstorm/phaser
synced 2024-11-22 04:33:31 +00:00
Added Collision Map support
This commit is contained in:
parent
a1579c8fd4
commit
de336e6d35
9 changed files with 349 additions and 33 deletions
|
@ -1,4 +1,4 @@
|
|||
var CHECKSUM = {
|
||||
build: '93f8c470-56db-11e7-a08e-87dbe325345b'
|
||||
build: 'a534dad0-56ea-11e7-93ca-31a05bf83d09'
|
||||
};
|
||||
module.exports = CHECKSUM;
|
|
@ -3,7 +3,6 @@
|
|||
var Class = require('../../utils/Class');
|
||||
var UpdateVelocity = require('./UpdateVelocity');
|
||||
var UpdateMotion = require('./UpdateMotion');
|
||||
var Trace = require('./Trace');
|
||||
var COLLIDES = require('./COLLIDES');
|
||||
var TYPE = require('./TYPE');
|
||||
|
||||
|
@ -18,14 +17,16 @@ var Body = new Class({
|
|||
|
||||
initialize:
|
||||
|
||||
function Body (world, x, y)
|
||||
function Body (world, x, y, sx, sy)
|
||||
{
|
||||
if (sx === undefined) { sx = 16; }
|
||||
if (sy === undefined) { sy = 16; }
|
||||
|
||||
this.world = world;
|
||||
|
||||
this.enabled = true;
|
||||
|
||||
this.size = { x: 16, y: 16 };
|
||||
this.offset = { x: 0, y: 0 };
|
||||
this.size = { x: sx, y: sy };
|
||||
this.pos = { x: x, y: y };
|
||||
this.last = { x: 0, y: 0 };
|
||||
this.vel = { x: 0, y: 0 };
|
||||
|
@ -57,7 +58,7 @@ var Body = new Class({
|
|||
var mx = this.vel.x * delta;
|
||||
var my = this.vel.y * delta;
|
||||
|
||||
var res = Trace(this.pos.x, this.pos.y, mx, my, this.size.x, this.size.y);
|
||||
var res = this.world.collisionMap.trace(this.pos.x, this.pos.y, mx, my, this.size.x, this.size.y);
|
||||
|
||||
UpdateMotion(this, res);
|
||||
},
|
||||
|
@ -77,6 +78,13 @@ var Body = new Class({
|
|||
);
|
||||
},
|
||||
|
||||
setBounce: function (value)
|
||||
{
|
||||
this.bounciness = value;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
setVelocityX: function (x)
|
||||
{
|
||||
this.vel.x = x;
|
||||
|
|
242
v3/src/physics/impact/CollisionMap.js
Normal file
242
v3/src/physics/impact/CollisionMap.js
Normal file
|
@ -0,0 +1,242 @@
|
|||
// Phaser.Physics.Impact.CollisionMap
|
||||
|
||||
var Class = require('../../utils/Class');
|
||||
var DefaultDefs = require('./DefaultDefs');
|
||||
|
||||
var CollisionMap = new Class({
|
||||
|
||||
initialize:
|
||||
|
||||
function CollisionMap (tilesize, data)
|
||||
{
|
||||
this.tilesize = tilesize;
|
||||
|
||||
this.data = data;
|
||||
|
||||
this.width = (Array.isArray(data)) ? data[0].length : 0;
|
||||
this.height = (Array.isArray(data)) ? data.length : 0;
|
||||
|
||||
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, y: y },
|
||||
tile: { x: 0, y: 0 }
|
||||
};
|
||||
|
||||
if (!this.data)
|
||||
{
|
||||
res.pos.x += vx;
|
||||
res.pos.y += vy;
|
||||
|
||||
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)
|
||||
{
|
||||
res.pos.x += vx;
|
||||
res.pos.y += vy;
|
||||
|
||||
var t = 0;
|
||||
var tilesize = this.tilesize;
|
||||
var width = this.width;
|
||||
var height = 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), height);
|
||||
var tileX = Math.floor((res.pos.x + pxOffsetX) / tilesize);
|
||||
|
||||
var prevTileX = Math.floor((x + pxOffsetX) / tilesize);
|
||||
|
||||
if (step > 0 || tileX == prevTileX || prevTileX < 0 || prevTileX >= width)
|
||||
{
|
||||
prevTileX = -1;
|
||||
}
|
||||
|
||||
if (tileX >= 0 && tileX < width)
|
||||
{
|
||||
for (var tileY = firstTileY; tileY < lastTileY; tileY++)
|
||||
{
|
||||
if (prevTileX != -1)
|
||||
{
|
||||
t = this.data[tileY][prevTileX];
|
||||
|
||||
if (t > 1 && this.checkDef(res, t, x, y, rvx, rvy, width, height, prevTileX, tileY))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
t = this.data[tileY][tileX];
|
||||
|
||||
if (t === 1 || (t > 1 && this.checkDef(res, t, x, y, rvx, rvy, width, height, tileX, tileY)))
|
||||
{
|
||||
if (t > 1 && res.collision.slope)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
res.collision.x = true;
|
||||
res.tile.x = t;
|
||||
res.pos.x = tileX * tilesize - pxOffsetX + tileOffsetX;
|
||||
|
||||
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), width);
|
||||
var tileY = Math.floor((res.pos.y + pxOffsetY) / tilesize);
|
||||
|
||||
var prevTileY = Math.floor((y + pxOffsetY) / tilesize);
|
||||
|
||||
if (step > 0 || tileY == prevTileY || prevTileY < 0 || prevTileY >= height)
|
||||
{
|
||||
prevTileY = -1;
|
||||
}
|
||||
|
||||
if (tileY >= 0 && tileY < height)
|
||||
{
|
||||
for (var tileX = firstTileX; tileX < lastTileX; tileX++)
|
||||
{
|
||||
if (prevTileY != -1)
|
||||
{
|
||||
t = this.data[prevTileY][tileX];
|
||||
|
||||
if (t > 1 && this.checkDef(res, t, x, y, rvx, rvy, width, height, tileX, prevTileY))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
t = this.data[tileY][tileX];
|
||||
|
||||
if (t == 1 || (t > 1 && this._checkTileDef(res, t, x, y, rvx, rvy, width, height, tileX, tileY)))
|
||||
{
|
||||
if (t > 1 && res.collision.slope)
|
||||
{
|
||||
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 true;
|
||||
}
|
||||
|
||||
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;
|
59
v3/src/physics/impact/DefaultDefs.js
Normal file
59
v3/src/physics/impact/DefaultDefs.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
var H = 0.5;
|
||||
var N = 1 / 3;
|
||||
var M = 2 / 3;
|
||||
|
||||
// Tile ID to Slope defs.
|
||||
// First 4 elements = line data, final = solid or non-solid behind the line
|
||||
|
||||
module.exports = {
|
||||
|
||||
2: [ 0, 1, 1, 0, true ],
|
||||
3: [ 0, 1, 1, H, true ],
|
||||
4: [ 0, H, 1, 0, true ],
|
||||
5: [ 0, 1, 1, M, true ],
|
||||
6: [ 0, M, 1, N, true ],
|
||||
7: [ 0, N, 1, 0, true ],
|
||||
8: [ H, 1, 0, 0, true ],
|
||||
9: [ 1, 0, H, 1, true ],
|
||||
10: [ H, 1, 1, 0, true ],
|
||||
11: [ 0, 0, H, 1, true ],
|
||||
12: [ 0, 0, 1, 0, false ],
|
||||
13: [ 1, 1, 0, 0, true ],
|
||||
14: [ 1, H, 0, 0, true ],
|
||||
15: [ 1, 1, 0, H, true ],
|
||||
16: [ 1, N, 0, 0, true ],
|
||||
17: [ 1, M, 0, N, true ],
|
||||
18: [ 1, 1, 0, M, true ],
|
||||
19: [ 1, 1, H, 0, true ],
|
||||
20: [ H, 0, 0, 1, true ],
|
||||
21: [ 0, 1, H, 0, true ],
|
||||
22: [ H, 0, 1, 1, true ],
|
||||
23: [ 1, 1, 0, 1, false ],
|
||||
24: [ 0, 0, 1, 1, true ],
|
||||
25: [ 0, 0, 1, H, true ],
|
||||
26: [ 0, H, 1, 1, true ],
|
||||
27: [ 0, 0, 1, N, true ],
|
||||
28: [ 0, N, 1, M, true ],
|
||||
29: [ 0, M, 1, 1, true ],
|
||||
30: [ N, 1, 0, 0, true ],
|
||||
31: [ 1, 0, M, 1, true ],
|
||||
32: [ M, 1, 1, 0, true ],
|
||||
33: [ 0, 0, N, 1, true ],
|
||||
34: [ 1, 0, 1, 1, false ],
|
||||
35: [ 1, 0, 0, 1, true ],
|
||||
36: [ 1, H, 0, 1, true ],
|
||||
37: [ 1, 0, 0, H, true ],
|
||||
38: [ 1, M, 0, 1, true ],
|
||||
39: [ 1, N, 0, M, true ],
|
||||
40: [ 1, 0, 0, N, true ],
|
||||
41: [ M, 1, N, 0, true ],
|
||||
42: [ M, 0, N, 1, true ],
|
||||
43: [ N, 1, M, 0, true ],
|
||||
44: [ N, 0, M, 1, true ],
|
||||
45: [ 0, 1, 0, 0, false ],
|
||||
52: [ 1, 1, M, 0, true ],
|
||||
53: [ N, 0, 0, 1, true ],
|
||||
54: [ 0, 1, N, 0, true ],
|
||||
55: [ M, 0, 1, 1, true ]
|
||||
|
||||
};
|
|
@ -1,4 +1,3 @@
|
|||
var Trace = require('./Trace');
|
||||
|
||||
var SeperateX = function (world, left, right, weak)
|
||||
{
|
||||
|
@ -11,7 +10,7 @@ var SeperateX = function (world, left, right, weak)
|
|||
|
||||
weak.vel.x = -weak.vel.x * weak.bounciness + strong.vel.x;
|
||||
|
||||
var resWeak = Trace(weak.pos.x, weak.pos.y, weak === left ? -nudge : nudge, 0, weak.size.x, weak.size.y);
|
||||
var resWeak = world.collisionMap.trace(weak.pos.x, weak.pos.y, weak === left ? -nudge : nudge, 0, weak.size.x, weak.size.y);
|
||||
|
||||
weak.pos.x = resWeak.pos.x;
|
||||
}
|
||||
|
@ -22,11 +21,11 @@ var SeperateX = function (world, left, right, weak)
|
|||
left.vel.x = -v2;
|
||||
right.vel.x = v2;
|
||||
|
||||
var resLeft = Trace(left.pos.x, left.pos.y, -nudge / 2, 0, left.size.x, left.size.y);
|
||||
var resLeft = world.collisionMap.trace(left.pos.x, left.pos.y, -nudge / 2, 0, left.size.x, left.size.y);
|
||||
|
||||
left.pos.x = Math.floor(resLeft.pos.x);
|
||||
|
||||
var resRight = Trace(right.pos.x, right.pos.y, nudge / 2, 0, right.size.x, right.size.y);
|
||||
var resRight = world.collisionMap.trace(right.pos.x, right.pos.y, nudge / 2, 0, right.size.x, right.size.y);
|
||||
|
||||
right.pos.x = Math.ceil(resRight.pos.x);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
var Trace = require('./Trace');
|
||||
|
||||
var SeperateY = function (world, top, bottom, weak)
|
||||
{
|
||||
|
@ -19,14 +18,14 @@ var SeperateY = function (world, top, bottom, weak)
|
|||
nudgeX = strong.vel.x * world.delta;
|
||||
}
|
||||
|
||||
var resWeak = Trace(weak.pos.x, weak.pos.y, nudgeX, weak == top ? -nudge : nudge, weak.size.x, weak.size.y);
|
||||
var resWeak = world.collisionMap.trace(weak.pos.x, weak.pos.y, nudgeX, weak == top ? -nudge : nudge, weak.size.x, weak.size.y);
|
||||
|
||||
weak.pos.y = resWeak.pos.y;
|
||||
weak.pos.x = resWeak.pos.x;
|
||||
}
|
||||
else if (world.gravity && (bottom.standing || top.vel.y > 0))
|
||||
{
|
||||
var resTop = Trace(top.pos.x, top.pos.y, 0, -(top.pos.y + top.size.y - bottom.pos.y), top.size.x, top.size.y);
|
||||
var resTop = world.collisionMap.trace(top.pos.x, top.pos.y, 0, -(top.pos.y + top.size.y - bottom.pos.y), top.size.x, top.size.y);
|
||||
|
||||
top.pos.y = resTop.pos.y;
|
||||
|
||||
|
@ -49,11 +48,11 @@ var SeperateY = function (world, top, bottom, weak)
|
|||
|
||||
var nudgeX = bottom.vel.x * world.delta;
|
||||
|
||||
var resTop = Trace(top.pos.x, top.pos.y, nudgeX, -nudge/2, top.size.x, top.size.y);
|
||||
var resTop = world.collisionMap.trace(top.pos.x, top.pos.y, nudgeX, -nudge/2, top.size.x, top.size.y);
|
||||
|
||||
top.pos.y = resTop.pos.y;
|
||||
|
||||
var resBottom = Trace(bottom.pos.x, bottom.pos.y, 0, nudge/2, bottom.size.x, bottom.size.y);
|
||||
var resBottom = world.collisionMap.trace(bottom.pos.x, bottom.pos.y, 0, nudge/2, bottom.size.x, bottom.size.y);
|
||||
|
||||
bottom.pos.y = resBottom.pos.y;
|
||||
}
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
var Trace = function (x, y, vx, vy)
|
||||
{
|
||||
return {
|
||||
collision: { x: false, y: false, slope: false },
|
||||
pos: { x: x + vx, y: y + vy },
|
||||
tile: { x: 0, y: 0 }
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = Trace;
|
|
@ -4,6 +4,7 @@ var Class = require('../../utils/Class');
|
|||
var Set = require('../../structs/Set');
|
||||
var Body = require('./Body');
|
||||
var Solver = require('./Solver');
|
||||
var CollisionMap = require('./CollisionMap');
|
||||
var COLLIDES = require('./COLLIDES');
|
||||
var TYPE = require('./TYPE');
|
||||
|
||||
|
@ -11,21 +12,26 @@ var World = new Class({
|
|||
|
||||
initialize:
|
||||
|
||||
function World ()
|
||||
function World (gravity, cellSize)
|
||||
{
|
||||
if (gravity === undefined) { gravity = 0; }
|
||||
if (cellSize === undefined) { cellSize = 64; }
|
||||
|
||||
this.bodies = new Set();
|
||||
|
||||
this.gravity = 0;
|
||||
|
||||
this.delta = 0;
|
||||
this.gravity = gravity;
|
||||
|
||||
// Spatial hash cell dimensions
|
||||
this.cellSize = 64;
|
||||
this.cellSize = cellSize;
|
||||
|
||||
this.collisionMap = new CollisionMap();
|
||||
|
||||
this.delta = 0;
|
||||
},
|
||||
|
||||
create: function (x, y)
|
||||
create: function (x, y, sizeX, sizeY)
|
||||
{
|
||||
var body = new Body(this, x, y);
|
||||
var body = new Body(this, x, y, sizeX, sizeY);
|
||||
|
||||
this.bodies.set(body);
|
||||
|
||||
|
|
|
@ -1,10 +1,23 @@
|
|||
// Phaser.Physics.Impact
|
||||
|
||||
// An Impact.js compatible physics world, body and solver, for those who are used
|
||||
// to the Impact way of defining and controlling physics bodies. Also works with
|
||||
// the new Loader support for Weltmeister map data.
|
||||
//
|
||||
// World updated to run off the Phaser main loop.
|
||||
// Body extended to support additional setter functions.
|
||||
//
|
||||
// To create the map data you'll need Weltmeister, which comes with Impact
|
||||
// and can be purchased from http://impactjs.com
|
||||
//
|
||||
// My thanks to Dominic Szablewski for his permission to support Impact in Phaser.
|
||||
|
||||
module.exports = {
|
||||
|
||||
Body: require('./Body'),
|
||||
World: require('./World'),
|
||||
COLLIDES: require('./COLLIDES'),
|
||||
CollisionMap: require('./CollisionMap'),
|
||||
TYPE: require('./TYPE'),
|
||||
World: require('./World')
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue