phaser/v3/src/physics/impact/World.js

358 lines
7.3 KiB
JavaScript
Raw Normal View History

2017-06-21 23:47:35 +00:00
// Phaser.Physics.Impact.World
var Body = require('./Body');
2017-06-21 23:47:35 +00:00
var Class = require('../../utils/Class');
var COLLIDES = require('./COLLIDES');
var CollisionMap = require('./CollisionMap');
2017-06-21 23:47:35 +00:00
var Set = require('../../structs/Set');
var Solver = require('./Solver');
var TYPE = require('./TYPE');
var World = new Class({
initialize:
2017-08-16 16:16:23 +00:00
function World (scene, gravity, cellSize, showDebug)
2017-06-21 23:47:35 +00:00
{
2017-06-22 01:40:10 +00:00
if (gravity === undefined) { gravity = 0; }
if (cellSize === undefined) { cellSize = 64; }
2017-08-16 16:16:23 +00:00
if (showDebug === undefined) { showDebug = false; }
2017-06-21 23:47:35 +00:00
this.scene = scene;
2017-08-16 15:30:28 +00:00
this.events = scene.sys.events;
2017-06-22 01:40:10 +00:00
this.bodies = new Set();
2017-06-21 23:47:35 +00:00
2017-06-22 01:40:10 +00:00
this.gravity = gravity;
2017-06-21 23:47:35 +00:00
// Spatial hash cell dimensions
2017-06-22 01:40:10 +00:00
this.cellSize = cellSize;
this.collisionMap = new CollisionMap();
this.delta = 0;
2017-08-16 15:30:28 +00:00
this.timeScale = 1;
// Impacts maximum time step is 20 fps.
this.maxStep = 0.05;
this.enabled = true;
2017-08-16 16:16:23 +00:00
this.drawDebug = false;
this.debugGraphic;
this._lastId = 0;
2017-08-16 16:16:23 +00:00
if (showDebug)
{
this.createDebugGraphic();
}
},
createDebugGraphic: function ()
{
var graphic = this.scene.sys.add.graphics({ x: 0, y: 0, lineStyle: { width: 1, color: 0x00ff00, alpha: 1 } });
2017-08-16 16:27:15 +00:00
graphic.setScrollFactor(0);
2017-08-16 16:16:23 +00:00
this.debugGraphic = graphic;
this.drawDebug = true;
return graphic;
},
getNextID: function ()
{
return this._lastId++;
2017-06-21 23:47:35 +00:00
},
2017-06-22 01:40:10 +00:00
create: function (x, y, sizeX, sizeY)
2017-06-21 23:47:35 +00:00
{
2017-06-22 01:40:10 +00:00
var body = new Body(this, x, y, sizeX, sizeY);
2017-06-21 23:47:35 +00:00
this.bodies.set(body);
return body;
},
2017-08-16 15:30:28 +00:00
pause: function ()
{
this.enabled = false;
return this;
},
resume: function ()
{
this.enabled = true;
return this;
},
2017-06-21 23:47:35 +00:00
update: function (time, delta)
{
2017-08-16 15:30:28 +00:00
if (!this.enabled || this.bodies.size === 0)
2017-06-21 23:47:35 +00:00
{
return;
}
2017-08-16 15:30:28 +00:00
// Impact uses a divided delta value that is clamped to the maxStep (20fps) maximum
this.delta = Math.min(delta / 1000, this.maxStep) * this.timeScale;
2017-06-21 23:47:35 +00:00
2017-08-16 15:30:28 +00:00
// Update all active bodies
2017-06-21 23:47:35 +00:00
var i;
var body;
var bodies = this.bodies.entries;
var len = bodies.length;
var hash = {};
var size = this.cellSize;
2017-08-16 16:16:23 +00:00
var debug = this.drawDebug;
if (debug)
{
this.debugGraphic.clear();
}
for (i = 0; i < len; i++)
2017-06-27 14:24:49 +00:00
{
body = bodies[i];
2017-06-21 23:47:35 +00:00
if (body.enabled)
{
2017-08-16 16:16:23 +00:00
body.update(this.delta, debug);
2017-06-21 23:47:35 +00:00
}
}
2017-06-21 23:47:35 +00:00
2017-08-16 15:30:28 +00:00
// Run collision against them all now they're in the new positions from the udpate
2017-06-21 23:47:35 +00:00
for (i = 0; i < len; i++)
2017-06-21 23:47:35 +00:00
{
body = bodies[i];
2017-06-21 23:47:35 +00:00
if (!body.skipHash())
2017-06-21 23:47:35 +00:00
{
this.checkHash(body, hash, size);
}
}
},
// Check the body against the spatial hash
checkHash: function (body, hash, size)
{
var checked = {};
2017-06-21 23:47:35 +00:00
var xmin = Math.floor(body.pos.x / size);
var ymin = Math.floor(body.pos.y / size);
var xmax = Math.floor((body.pos.x + body.size.x) / size) + 1;
var ymax = Math.floor((body.pos.y + body.size.y) / size) + 1;
for (var x = xmin; x < xmax; x++)
{
for (var y = ymin; y < ymax; y++)
{
if (!hash[x])
{
hash[x] = {};
2017-06-23 17:08:22 +00:00
hash[x][y] = [ body ];
2017-06-21 23:47:35 +00:00
}
else if (!hash[x][y])
{
2017-06-23 17:08:22 +00:00
hash[x][y] = [ body ];
2017-06-21 23:47:35 +00:00
}
else
{
var cell = hash[x][y];
for (var c = 0; c < cell.length; c++)
{
if (body.touches(cell[c]) && !checked[cell[c].id])
{
checked[cell[c].id] = true;
this.checkBodies(body, cell[c]);
}
}
cell.push(body);
}
}
}
},
checkBodies: function (bodyA, bodyB)
{
// bitwise checks
if (bodyA.checkAgainst & bodyB.type)
{
bodyA.check(bodyB);
}
if (bodyB.checkAgainst & bodyA.type)
{
bodyB.check(bodyA);
}
if (bodyA.collides && bodyB.collides && bodyA.collides + bodyB.collides > COLLIDES.ACTIVE)
{
Solver(this, bodyA, bodyB);
}
2017-08-16 00:20:35 +00:00
},
//////////////
// Helpers //
//////////////
setCollidesNever: function (bodies)
{
for (var i = 0; i < bodies.length; i++)
{
bodies[i].collides = COLLIDES.NEVER;
}
return this;
},
setLite: function (bodies)
{
for (var i = 0; i < bodies.length; i++)
{
bodies[i].collides = COLLIDES.LITE;
}
return this;
},
setPassive: function (bodies)
{
for (var i = 0; i < bodies.length; i++)
{
bodies[i].collides = COLLIDES.PASSIVE;
}
return this;
},
setActive: function (bodies)
{
for (var i = 0; i < bodies.length; i++)
{
bodies[i].collides = COLLIDES.ACTIVE;
}
return this;
},
setFixed: function (bodies)
{
for (var i = 0; i < bodies.length; i++)
{
bodies[i].collides = COLLIDES.FIXED;
}
return this;
},
setTypeNone: function (bodies)
{
for (var i = 0; i < bodies.length; i++)
{
bodies[i].type = TYPE.NONE;
}
return this;
},
setTypeA: function (bodies)
{
for (var i = 0; i < bodies.length; i++)
{
bodies[i].type = TYPE.A;
}
return this;
},
setTypeB: function (bodies)
{
for (var i = 0; i < bodies.length; i++)
{
bodies[i].type = TYPE.B;
}
return this;
},
setAvsB: function (bodies)
{
for (var i = 0; i < bodies.length; i++)
{
bodies[i].type = TYPE.A;
bodies[i].checkAgainst = TYPE.B;
}
return this;
},
setBvsA: function (bodies)
{
for (var i = 0; i < bodies.length; i++)
{
bodies[i].type = TYPE.B;
bodies[i].checkAgainst = TYPE.A;
}
return this;
},
setCheckAgainstNone: function (bodies)
{
for (var i = 0; i < bodies.length; i++)
{
bodies[i].checkAgainst = TYPE.NONE;
}
return this;
},
setCheckAgainstA: function (bodies)
{
for (var i = 0; i < bodies.length; i++)
{
bodies[i].checkAgainst = TYPE.A;
}
return this;
},
setCheckAgainstB: function (bodies)
{
for (var i = 0; i < bodies.length; i++)
{
bodies[i].checkAgainst = TYPE.B;
}
return this;
2017-08-16 16:16:23 +00:00
},
destroy: function ()
{
this.scene = null;
this.events = null;
this.bodies.clear();
this.bodies = null;
this.collisionMap = null;
2017-06-21 23:47:35 +00:00
}
});
module.exports = World;