lance-gg
Version:
A Node.js based real-time multiplayer game server
1,685 lines (1,485 loc) • 1.03 MB
JavaScript
class GameWorld {
constructor() {
this.stepCount = 0;
this.objects = {};
this.playerCount = 0;
this.idCount = 0;
}
getNewId() {
let possibleId = this.idCount;
while (possibleId in this.objects)
possibleId++;
this.idCount = possibleId + 1;
return possibleId;
}
queryOneObject(query) {
let objs = this.queryObjects(query);
return objs.length > 0 ? objs[0] : null;
}
queryObjects(query) {
let queriedObjects = [];
this.forEachObject((id, object) => {
let conditions = [];
conditions.push(!('id' in query) || query.id !== null && object.id === query.id);
conditions.push(!('playerId' in query) || query.playerId !== null && object.playerId === query.playerId);
conditions.push(!('instanceType' in query) || query.instanceType !== null && object instanceof query.instanceType);
if ('components' in query) {
query.components.forEach(componentClass => {
conditions.push(object.hasComponent(componentClass));
});
}
if (conditions.every(value => value)) {
queriedObjects.push(object);
if (query.returnSingle)
return false;
}
});
return queriedObjects;
}
queryObject(query) {
return this.queryObjects(Object.assign(query, {
returnSingle: true
}));
}
addObject(object) {
this.objects[object.id] = object;
}
removeObject(id) {
delete this.objects[id];
}
forEachObject(callback) {
for (let id of Object.keys(this.objects)) {
let returnValue = callback(id, this.objects[id]);
if (returnValue === false)
break;
}
}
}
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
var eventEmitter = {exports: {}};
var d$1 = {exports: {}};
// ES3 safe
var _undefined$1 = void 0;
var is$4 = function (value) { return value !== _undefined$1 && value !== null; };
var isValue$3 = is$4;
// prettier-ignore
var possibleTypes = { "object": true, "function": true, "undefined": true /* document.all */ };
var is$3 = function (value) {
if (!isValue$3(value)) return false;
return hasOwnProperty.call(possibleTypes, typeof value);
};
var isObject$1 = is$3;
var is$2 = function (value) {
if (!isObject$1(value)) return false;
try {
if (!value.constructor) return false;
return value.constructor.prototype === value;
} catch (error) {
return false;
}
};
var isPrototype = is$2;
var is$1 = function (value) {
if (typeof value !== "function") return false;
if (!hasOwnProperty.call(value, "length")) return false;
try {
if (typeof value.length !== "number") return false;
if (typeof value.call !== "function") return false;
if (typeof value.apply !== "function") return false;
} catch (error) {
return false;
}
return !isPrototype(value);
};
var isFunction = is$1;
var classRe = /^\s*class[\s{/}]/, functionToString = Function.prototype.toString;
var is = function (value) {
if (!isFunction(value)) return false;
if (classRe.test(functionToString.call(value))) return false;
return true;
};
var isImplemented$2 = function () {
var assign = Object.assign, obj;
if (typeof assign !== "function") return false;
obj = { foo: "raz" };
assign(obj, { bar: "dwa" }, { trzy: "trzy" });
return obj.foo + obj.bar + obj.trzy === "razdwatrzy";
};
var isImplemented$1;
var hasRequiredIsImplemented;
function requireIsImplemented () {
if (hasRequiredIsImplemented) return isImplemented$1;
hasRequiredIsImplemented = 1;
isImplemented$1 = function () {
try {
Object.keys("primitive");
return true;
} catch (e) {
return false;
}
};
return isImplemented$1;
}
// eslint-disable-next-line no-empty-function
var noop = function () {};
var _undefined = noop(); // Support ES3 engines
var isValue$2 = function (val) { return val !== _undefined && val !== null; };
var shim$2;
var hasRequiredShim$2;
function requireShim$2 () {
if (hasRequiredShim$2) return shim$2;
hasRequiredShim$2 = 1;
var isValue = isValue$2;
var keys = Object.keys;
shim$2 = function (object) { return keys(isValue(object) ? Object(object) : object); };
return shim$2;
}
var keys;
var hasRequiredKeys;
function requireKeys () {
if (hasRequiredKeys) return keys;
hasRequiredKeys = 1;
keys = requireIsImplemented()() ? Object.keys : requireShim$2();
return keys;
}
var validValue;
var hasRequiredValidValue;
function requireValidValue () {
if (hasRequiredValidValue) return validValue;
hasRequiredValidValue = 1;
var isValue = isValue$2;
validValue = function (value) {
if (!isValue(value)) throw new TypeError("Cannot use null or undefined");
return value;
};
return validValue;
}
var shim$1;
var hasRequiredShim$1;
function requireShim$1 () {
if (hasRequiredShim$1) return shim$1;
hasRequiredShim$1 = 1;
var keys = requireKeys()
, value = requireValidValue()
, max = Math.max;
shim$1 = function (dest, src /*, …srcn*/) {
var error, i, length = max(arguments.length, 2), assign;
dest = Object(value(dest));
assign = function (key) {
try {
dest[key] = src[key];
} catch (e) {
if (!error) error = e;
}
};
for (i = 1; i < length; ++i) {
src = arguments[i];
keys(src).forEach(assign);
}
if (error !== undefined) throw error;
return dest;
};
return shim$1;
}
var assign$1 = isImplemented$2() ? Object.assign : requireShim$1();
var isValue$1 = isValue$2;
var forEach = Array.prototype.forEach, create = Object.create;
var process = function (src, obj) {
var key;
for (key in src) obj[key] = src[key];
};
// eslint-disable-next-line no-unused-vars
var normalizeOptions = function (opts1 /*, …options*/) {
var result = create(null);
forEach.call(arguments, function (options) {
if (!isValue$1(options)) return;
process(Object(options), result);
});
return result;
};
var str = "razdwatrzy";
var isImplemented = function () {
if (typeof str.contains !== "function") return false;
return str.contains("dwa") === true && str.contains("foo") === false;
};
var shim;
var hasRequiredShim;
function requireShim () {
if (hasRequiredShim) return shim;
hasRequiredShim = 1;
var indexOf = String.prototype.indexOf;
shim = function (searchString /*, position*/) {
return indexOf.call(this, searchString, arguments[1]) > -1;
};
return shim;
}
var contains$1 = isImplemented() ? String.prototype.contains : requireShim();
var isValue = is$4
, isPlainFunction = is
, assign = assign$1
, normalizeOpts = normalizeOptions
, contains = contains$1;
var d = (d$1.exports = function (dscr, value/*, options*/) {
var c, e, w, options, desc;
if (arguments.length < 2 || typeof dscr !== "string") {
options = value;
value = dscr;
dscr = null;
} else {
options = arguments[2];
}
if (isValue(dscr)) {
c = contains.call(dscr, "c");
e = contains.call(dscr, "e");
w = contains.call(dscr, "w");
} else {
c = w = true;
e = false;
}
desc = { value: value, configurable: c, enumerable: e, writable: w };
return !options ? desc : assign(normalizeOpts(options), desc);
});
d.gs = function (dscr, get, set/*, options*/) {
var c, e, options, desc;
if (typeof dscr !== "string") {
options = set;
set = get;
get = dscr;
dscr = null;
} else {
options = arguments[3];
}
if (!isValue(get)) {
get = undefined;
} else if (!isPlainFunction(get)) {
options = get;
get = set = undefined;
} else if (!isValue(set)) {
set = undefined;
} else if (!isPlainFunction(set)) {
options = set;
set = undefined;
}
if (isValue(dscr)) {
c = contains.call(dscr, "c");
e = contains.call(dscr, "e");
} else {
c = true;
e = false;
}
desc = { get: get, set: set, configurable: c, enumerable: e };
return !options ? desc : assign(normalizeOpts(options), desc);
};
var dExports = d$1.exports;
var validCallable = function (fn) {
if (typeof fn !== "function") throw new TypeError(fn + " is not a function");
return fn;
};
(function (module, exports) {
var d = dExports
, callable = validCallable
, apply = Function.prototype.apply, call = Function.prototype.call
, create = Object.create, defineProperty = Object.defineProperty
, defineProperties = Object.defineProperties
, hasOwnProperty = Object.prototype.hasOwnProperty
, descriptor = { configurable: true, enumerable: false, writable: true }
, on, once, off, emit, methods, descriptors, base;
on = function (type, listener) {
var data;
callable(listener);
if (!hasOwnProperty.call(this, '__ee__')) {
data = descriptor.value = create(null);
defineProperty(this, '__ee__', descriptor);
descriptor.value = null;
} else {
data = this.__ee__;
}
if (!data[type]) data[type] = listener;
else if (typeof data[type] === 'object') data[type].push(listener);
else data[type] = [data[type], listener];
return this;
};
once = function (type, listener) {
var once, self;
callable(listener);
self = this;
on.call(this, type, once = function () {
off.call(self, type, once);
apply.call(listener, this, arguments);
});
once.__eeOnceListener__ = listener;
return this;
};
off = function (type, listener) {
var data, listeners, candidate, i;
callable(listener);
if (!hasOwnProperty.call(this, '__ee__')) return this;
data = this.__ee__;
if (!data[type]) return this;
listeners = data[type];
if (typeof listeners === 'object') {
for (i = 0; (candidate = listeners[i]); ++i) {
if ((candidate === listener) ||
(candidate.__eeOnceListener__ === listener)) {
if (listeners.length === 2) data[type] = listeners[i ? 0 : 1];
else listeners.splice(i, 1);
}
}
} else {
if ((listeners === listener) ||
(listeners.__eeOnceListener__ === listener)) {
delete data[type];
}
}
return this;
};
emit = function (type) {
var i, l, listener, listeners, args;
if (!hasOwnProperty.call(this, '__ee__')) return;
listeners = this.__ee__[type];
if (!listeners) return;
if (typeof listeners === 'object') {
l = arguments.length;
args = new Array(l - 1);
for (i = 1; i < l; ++i) args[i - 1] = arguments[i];
listeners = listeners.slice();
for (i = 0; (listener = listeners[i]); ++i) {
apply.call(listener, this, args);
}
} else {
switch (arguments.length) {
case 1:
call.call(listeners, this);
break;
case 2:
call.call(listeners, this, arguments[1]);
break;
case 3:
call.call(listeners, this, arguments[1], arguments[2]);
break;
default:
l = arguments.length;
args = new Array(l - 1);
for (i = 1; i < l; ++i) {
args[i - 1] = arguments[i];
}
apply.call(listeners, this, args);
}
}
};
methods = {
on: on,
once: once,
off: off,
emit: emit
};
descriptors = {
on: d(on),
once: d(once),
off: d(off),
emit: d(emit)
};
base = defineProperties({}, descriptors);
module.exports = exports = function (o) {
return (o == null) ? create(base) : defineProperties(Object(o), descriptors);
};
exports.methods = methods;
} (eventEmitter, eventEmitter.exports));
var eventEmitterExports = eventEmitter.exports;
var EventEmitter$4 = /*@__PURE__*/getDefaultExportFromCjs(eventEmitterExports);
class Timer {
constructor() {
this.currentTime = 0;
this.isActive = false;
this.idCounter = 0;
this.events = {};
}
play() {
this.isActive = true;
}
tick() {
let event;
let eventId;
if (this.isActive) {
this.currentTime++;
for (eventId in this.events) {
event = this.events[eventId];
if (event) {
if (event.type == 'repeat') {
if ((this.currentTime - event.startOffset) % event.time == 0) {
event.callback.apply(event.thisContext, event.args);
}
}
if (event.type == 'single') {
if ((this.currentTime - event.startOffset) % event.time == 0) {
event.callback.apply(event.thisContext, event.args);
event.destroy();
}
}
}
}
}
}
destroyEvent(eventId) {
delete this.events[eventId];
}
loop(time, callback) {
let timerEvent = new TimerEvent(this, 'repeat', time, callback);
this.events[timerEvent.id] = timerEvent;
return timerEvent;
}
add(time, callback, thisContext, args) {
let timerEvent = new TimerEvent(this, 'single', time, callback, thisContext, args);
this.events[timerEvent.id] = timerEvent;
return timerEvent;
}
destroy(id) {
delete this.events[id];
}
}
class TimerEvent {
constructor(timer, type, time, callback, thisContext = null, args = null) {
this.id = ++timer.idCounter;
this.timer = timer;
this.type = type;
this.time = time;
this.callback = callback;
this.startOffset = timer.currentTime;
this.thisContext = thisContext;
this.args = args;
this.destroy = function () {
this.timer.destroy(this.id);
};
}
}
class Trace {
constructor(options) {
this.options = Object.assign({
traceLevel: Trace.TRACE_DEBUG
}, options);
this.traceBuffer = [];
this.step = 'initializing';
this.error = this.trace.bind(this, Trace.TRACE_ERROR);
this.warn = this.trace.bind(this, Trace.TRACE_WARN);
this.info = this.trace.bind(this, Trace.TRACE_INFO);
this.debug = this.trace.bind(this, Trace.TRACE_DEBUG);
this.trace = this.trace.bind(this, Trace.TRACE_ALL);
}
static get TRACE_ALL() { return 0; }
static get TRACE_DEBUG() { return 1; }
static get TRACE_INFO() { return 2; }
static get TRACE_WARN() { return 3; }
static get TRACE_ERROR() { return 4; }
static get TRACE_NONE() { return 1000; }
trace(level, dataCB) {
if (level < this.options.traceLevel)
return;
this.traceBuffer.push({ data: dataCB(), level, step: this.step, time: new Date() });
}
rotate() {
let buffer = this.traceBuffer;
this.traceBuffer = [];
return buffer;
}
get length() {
return this.traceBuffer.length;
}
setStep(s) {
this.step = s;
}
}
class GameEngine {
constructor(options) {
const isServerSide = (typeof window === 'undefined');
const glob = isServerSide ? global : window;
glob.LANCE = { gameEngine: this };
const defaultOpts = { traceLevel: Trace.TRACE_NONE, clientIDSpace: NaN };
if (!isServerSide)
defaultOpts.clientIDSpace = 1000000;
this.options = Object.assign(defaultOpts, options);
this.playerId = NaN;
let eventEmitter = EventEmitter$4();
this.on = eventEmitter.on;
this.once = eventEmitter.once;
this.removeListener = eventEmitter.off;
this.off = eventEmitter.off;
this.emit = eventEmitter.emit;
this.trace = new Trace({ traceLevel: this.options.traceLevel });
}
findLocalShadow(serverObj) {
for (let localId of Object.keys(this.world.objects)) {
if (Number(localId) < this.options.clientIDSpace)
continue;
let localObj = this.world.objects[localId];
if (localObj.hasOwnProperty('inputId') && localObj.inputId === serverObj.inputId)
return localObj;
}
return null;
}
initWorld(worldSettings) {
this.world = new GameWorld();
if (this.options.clientIDSpace) {
this.world.idCount = this.options.clientIDSpace;
}
this.worldSettings = Object.assign({}, worldSettings);
}
start() {
this.trace.info(() => '========== game engine started ==========');
this.initWorld();
this.timer = new Timer();
this.timer.play();
this.on('postStep', (step, isReenact) => {
if (!isReenact)
this.timer.tick();
});
this.emit('start', { timestamp: (new Date()).getTime() });
}
step(isReenact, t, dt, physicsOnly) {
if (physicsOnly && dt) {
if (dt)
dt /= 1000;
this.physicsEngine.step(dt, objectFilter);
return;
}
if (isReenact === undefined)
throw new Error('game engine does not forward argument isReenact to super class');
isReenact = Boolean(isReenact);
let step = ++this.world.stepCount;
let clientIDSpace = this.options.clientIDSpace;
let preStepDesc = { step, isReenact, dt };
this.emit('preStep', preStepDesc);
function objectFilter(o) {
return !isReenact || o.id < clientIDSpace;
}
if (this.physicsEngine && !this.ignorePhysics) {
if (dt)
dt /= 1000;
this.physicsEngine.step(dt, objectFilter);
}
this.world.forEachObject((id, o) => {
if (typeof o.refreshFromPhysics === 'function')
o.refreshFromPhysics();
this.trace.trace(() => `object[${id}] after ${isReenact ? 'reenact' : 'step'} : ${o.toString()}`);
});
this.emit('postStep', { step, isReenact });
}
addObjectToWorld(object) {
if (Number(object.id) >= this.options.clientIDSpace) {
let serverCopyArrived = false;
this.world.forEachObject((id, o) => {
if (o.hasOwnProperty('inputId') && o.inputId === object.inputId) {
serverCopyArrived = true;
return false;
}
});
if (serverCopyArrived) {
this.trace.info(() => `========== shadow object NOT added ${object.toString()} ==========`);
return null;
}
}
this.world.addObject(object);
if (typeof object.onAddToWorld === 'function')
object.onAddToWorld(this);
this.emit('objectAdded', object);
this.trace.info(() => `========== object added ${object.toString()} ==========`);
return object;
}
processInput(inputDesc, playerId, isServer) {
this.trace.info(() => `game engine processing input[${inputDesc.messageIndex}] <${inputDesc.input}> from playerId ${playerId}`);
}
removeObjectFromWorld(objectId) {
if (typeof objectId === 'object')
objectId = objectId.id;
let object = this.world.objects[objectId];
if (!object) {
throw new Error(`Game attempted to remove a game object which doesn't (or never did) exist, id=${objectId}`);
}
this.trace.info(() => `========== destroying object ${object.toString()} ==========`);
if (typeof object.onRemoveFromWorld === 'function')
object.onRemoveFromWorld(this);
this.emit('objectDestroyed', object);
this.world.removeObject(objectId);
}
isOwnedByPlayer(object) {
return (object.playerId == this.playerId);
}
registerClasses(serializer) {
}
getPlayerGameOverResult() {
return null;
}
}
class PhysicsEngine {
constructor(options) {
this.options = options;
this.gameEngine = options.gameEngine;
if (!options.gameEngine) {
console.warn('Physics engine initialized without gameEngine!');
}
}
step(dt, objectFilter) { }
}
function commonjsRequire(path) {
throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');
}
var cannon = {exports: {}};
/*
* Copyright (c) 2015 cannon.js Authors
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
(function (module, exports) {
!function(e){module.exports=e();}(function(){return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof commonjsRequire=="function"&&commonjsRequire;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r);}return n[o].exports}var i=typeof commonjsRequire=="function"&&commonjsRequire;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
module.exports={
"name": "cannon",
"version": "0.6.2",
"description": "A lightweight 3D physics engine written in JavaScript.",
"homepage": "https://github.com/schteppe/cannon.js",
"author": "Stefan Hedman <schteppe@gmail.com> (http://steffe.se)",
"keywords": [
"cannon.js",
"cannon",
"physics",
"engine",
"3d"
],
"main": "./build/cannon.js",
"engines": {
"node": "*"
},
"repository": {
"type": "git",
"url": "https://github.com/schteppe/cannon.js.git"
},
"bugs": {
"url": "https://github.com/schteppe/cannon.js/issues"
},
"licenses": [
{
"type": "MIT"
}
],
"devDependencies": {
"jshint": "latest",
"uglify-js": "latest",
"nodeunit": "^0.9.0",
"grunt": "~0.4.0",
"grunt-contrib-jshint": "~0.1.1",
"grunt-contrib-nodeunit": "^0.4.1",
"grunt-contrib-concat": "~0.1.3",
"grunt-contrib-uglify": "^0.5.1",
"grunt-browserify": "^2.1.4",
"grunt-contrib-yuidoc": "^0.5.2",
"browserify": "*"
},
"dependencies": {}
};
},{}],2:[function(_dereq_,module,exports){
// Export classes
module.exports = {
version : _dereq_('../package.json').version,
AABB : _dereq_('./collision/AABB'),
ArrayCollisionMatrix : _dereq_('./collision/ArrayCollisionMatrix'),
Body : _dereq_('./objects/Body'),
Box : _dereq_('./shapes/Box'),
Broadphase : _dereq_('./collision/Broadphase'),
Constraint : _dereq_('./constraints/Constraint'),
ContactEquation : _dereq_('./equations/ContactEquation'),
Narrowphase : _dereq_('./world/Narrowphase'),
ConeTwistConstraint : _dereq_('./constraints/ConeTwistConstraint'),
ContactMaterial : _dereq_('./material/ContactMaterial'),
ConvexPolyhedron : _dereq_('./shapes/ConvexPolyhedron'),
Cylinder : _dereq_('./shapes/Cylinder'),
DistanceConstraint : _dereq_('./constraints/DistanceConstraint'),
Equation : _dereq_('./equations/Equation'),
EventTarget : _dereq_('./utils/EventTarget'),
FrictionEquation : _dereq_('./equations/FrictionEquation'),
GSSolver : _dereq_('./solver/GSSolver'),
GridBroadphase : _dereq_('./collision/GridBroadphase'),
Heightfield : _dereq_('./shapes/Heightfield'),
HingeConstraint : _dereq_('./constraints/HingeConstraint'),
LockConstraint : _dereq_('./constraints/LockConstraint'),
Mat3 : _dereq_('./math/Mat3'),
Material : _dereq_('./material/Material'),
NaiveBroadphase : _dereq_('./collision/NaiveBroadphase'),
ObjectCollisionMatrix : _dereq_('./collision/ObjectCollisionMatrix'),
Pool : _dereq_('./utils/Pool'),
Particle : _dereq_('./shapes/Particle'),
Plane : _dereq_('./shapes/Plane'),
PointToPointConstraint : _dereq_('./constraints/PointToPointConstraint'),
Quaternion : _dereq_('./math/Quaternion'),
Ray : _dereq_('./collision/Ray'),
RaycastVehicle : _dereq_('./objects/RaycastVehicle'),
RaycastResult : _dereq_('./collision/RaycastResult'),
RigidVehicle : _dereq_('./objects/RigidVehicle'),
RotationalEquation : _dereq_('./equations/RotationalEquation'),
RotationalMotorEquation : _dereq_('./equations/RotationalMotorEquation'),
SAPBroadphase : _dereq_('./collision/SAPBroadphase'),
SPHSystem : _dereq_('./objects/SPHSystem'),
Shape : _dereq_('./shapes/Shape'),
Solver : _dereq_('./solver/Solver'),
Sphere : _dereq_('./shapes/Sphere'),
SplitSolver : _dereq_('./solver/SplitSolver'),
Spring : _dereq_('./objects/Spring'),
Trimesh : _dereq_('./shapes/Trimesh'),
Vec3 : _dereq_('./math/Vec3'),
Vec3Pool : _dereq_('./utils/Vec3Pool'),
World : _dereq_('./world/World'),
};
},{"../package.json":1,"./collision/AABB":3,"./collision/ArrayCollisionMatrix":4,"./collision/Broadphase":5,"./collision/GridBroadphase":6,"./collision/NaiveBroadphase":7,"./collision/ObjectCollisionMatrix":8,"./collision/Ray":9,"./collision/RaycastResult":10,"./collision/SAPBroadphase":11,"./constraints/ConeTwistConstraint":12,"./constraints/Constraint":13,"./constraints/DistanceConstraint":14,"./constraints/HingeConstraint":15,"./constraints/LockConstraint":16,"./constraints/PointToPointConstraint":17,"./equations/ContactEquation":19,"./equations/Equation":20,"./equations/FrictionEquation":21,"./equations/RotationalEquation":22,"./equations/RotationalMotorEquation":23,"./material/ContactMaterial":24,"./material/Material":25,"./math/Mat3":27,"./math/Quaternion":28,"./math/Vec3":30,"./objects/Body":31,"./objects/RaycastVehicle":32,"./objects/RigidVehicle":33,"./objects/SPHSystem":34,"./objects/Spring":35,"./shapes/Box":37,"./shapes/ConvexPolyhedron":38,"./shapes/Cylinder":39,"./shapes/Heightfield":40,"./shapes/Particle":41,"./shapes/Plane":42,"./shapes/Shape":43,"./shapes/Sphere":44,"./shapes/Trimesh":45,"./solver/GSSolver":46,"./solver/Solver":47,"./solver/SplitSolver":48,"./utils/EventTarget":49,"./utils/Pool":51,"./utils/Vec3Pool":54,"./world/Narrowphase":55,"./world/World":56}],3:[function(_dereq_,module,exports){
var Vec3 = _dereq_('../math/Vec3');
_dereq_('../utils/Utils');
module.exports = AABB;
/**
* Axis aligned bounding box class.
* @class AABB
* @constructor
* @param {Object} [options]
* @param {Vec3} [options.upperBound]
* @param {Vec3} [options.lowerBound]
*/
function AABB(options){
options = options || {};
/**
* The lower bound of the bounding box.
* @property lowerBound
* @type {Vec3}
*/
this.lowerBound = new Vec3();
if(options.lowerBound){
this.lowerBound.copy(options.lowerBound);
}
/**
* The upper bound of the bounding box.
* @property upperBound
* @type {Vec3}
*/
this.upperBound = new Vec3();
if(options.upperBound){
this.upperBound.copy(options.upperBound);
}
}
var tmp = new Vec3();
/**
* Set the AABB bounds from a set of points.
* @method setFromPoints
* @param {Array} points An array of Vec3's.
* @param {Vec3} position
* @param {Quaternion} quaternion
* @param {number} skinSize
* @return {AABB} The self object
*/
AABB.prototype.setFromPoints = function(points, position, quaternion, skinSize){
var l = this.lowerBound,
u = this.upperBound,
q = quaternion;
// Set to the first point
l.copy(points[0]);
if(q){
q.vmult(l, l);
}
u.copy(l);
for(var i = 1; i<points.length; i++){
var p = points[i];
if(q){
q.vmult(p, tmp);
p = tmp;
}
if(p.x > u.x){ u.x = p.x; }
if(p.x < l.x){ l.x = p.x; }
if(p.y > u.y){ u.y = p.y; }
if(p.y < l.y){ l.y = p.y; }
if(p.z > u.z){ u.z = p.z; }
if(p.z < l.z){ l.z = p.z; }
}
// Add offset
if (position) {
position.vadd(l, l);
position.vadd(u, u);
}
if(skinSize){
l.x -= skinSize;
l.y -= skinSize;
l.z -= skinSize;
u.x += skinSize;
u.y += skinSize;
u.z += skinSize;
}
return this;
};
/**
* Copy bounds from an AABB to this AABB
* @method copy
* @param {AABB} aabb Source to copy from
* @return {AABB} The this object, for chainability
*/
AABB.prototype.copy = function(aabb){
this.lowerBound.copy(aabb.lowerBound);
this.upperBound.copy(aabb.upperBound);
return this;
};
/**
* Clone an AABB
* @method clone
*/
AABB.prototype.clone = function(){
return new AABB().copy(this);
};
/**
* Extend this AABB so that it covers the given AABB too.
* @method extend
* @param {AABB} aabb
*/
AABB.prototype.extend = function(aabb){
// Extend lower bound
var l = aabb.lowerBound.x;
if(this.lowerBound.x > l){
this.lowerBound.x = l;
}
// Upper
var u = aabb.upperBound.x;
if(this.upperBound.x < u){
this.upperBound.x = u;
}
// Extend lower bound
var l = aabb.lowerBound.y;
if(this.lowerBound.y > l){
this.lowerBound.y = l;
}
// Upper
var u = aabb.upperBound.y;
if(this.upperBound.y < u){
this.upperBound.y = u;
}
// Extend lower bound
var l = aabb.lowerBound.z;
if(this.lowerBound.z > l){
this.lowerBound.z = l;
}
// Upper
var u = aabb.upperBound.z;
if(this.upperBound.z < u){
this.upperBound.z = u;
}
};
/**
* Returns true if the given AABB overlaps this AABB.
* @method overlaps
* @param {AABB} aabb
* @return {Boolean}
*/
AABB.prototype.overlaps = function(aabb){
var l1 = this.lowerBound,
u1 = this.upperBound,
l2 = aabb.lowerBound,
u2 = aabb.upperBound;
// l2 u2
// |---------|
// |--------|
// l1 u1
return ((l2.x <= u1.x && u1.x <= u2.x) || (l1.x <= u2.x && u2.x <= u1.x)) &&
((l2.y <= u1.y && u1.y <= u2.y) || (l1.y <= u2.y && u2.y <= u1.y)) &&
((l2.z <= u1.z && u1.z <= u2.z) || (l1.z <= u2.z && u2.z <= u1.z));
};
/**
* Returns true if the given AABB is fully contained in this AABB.
* @method contains
* @param {AABB} aabb
* @return {Boolean}
*/
AABB.prototype.contains = function(aabb){
var l1 = this.lowerBound,
u1 = this.upperBound,
l2 = aabb.lowerBound,
u2 = aabb.upperBound;
// l2 u2
// |---------|
// |---------------|
// l1 u1
return (
(l1.x <= l2.x && u1.x >= u2.x) &&
(l1.y <= l2.y && u1.y >= u2.y) &&
(l1.z <= l2.z && u1.z >= u2.z)
);
};
/**
* @method getCorners
* @param {Vec3} a
* @param {Vec3} b
* @param {Vec3} c
* @param {Vec3} d
* @param {Vec3} e
* @param {Vec3} f
* @param {Vec3} g
* @param {Vec3} h
*/
AABB.prototype.getCorners = function(a, b, c, d, e, f, g, h){
var l = this.lowerBound,
u = this.upperBound;
a.copy(l);
b.set( u.x, l.y, l.z );
c.set( u.x, u.y, l.z );
d.set( l.x, u.y, u.z );
e.set( u.x, l.y, l.z );
f.set( l.x, u.y, l.z );
g.set( l.x, l.y, u.z );
h.copy(u);
};
var transformIntoFrame_corners = [
new Vec3(),
new Vec3(),
new Vec3(),
new Vec3(),
new Vec3(),
new Vec3(),
new Vec3(),
new Vec3()
];
/**
* Get the representation of an AABB in another frame.
* @method toLocalFrame
* @param {Transform} frame
* @param {AABB} target
* @return {AABB} The "target" AABB object.
*/
AABB.prototype.toLocalFrame = function(frame, target){
var corners = transformIntoFrame_corners;
var a = corners[0];
var b = corners[1];
var c = corners[2];
var d = corners[3];
var e = corners[4];
var f = corners[5];
var g = corners[6];
var h = corners[7];
// Get corners in current frame
this.getCorners(a, b, c, d, e, f, g, h);
// Transform them to new local frame
for(var i=0; i !== 8; i++){
var corner = corners[i];
frame.pointToLocal(corner, corner);
}
return target.setFromPoints(corners);
};
/**
* Get the representation of an AABB in the global frame.
* @method toWorldFrame
* @param {Transform} frame
* @param {AABB} target
* @return {AABB} The "target" AABB object.
*/
AABB.prototype.toWorldFrame = function(frame, target){
var corners = transformIntoFrame_corners;
var a = corners[0];
var b = corners[1];
var c = corners[2];
var d = corners[3];
var e = corners[4];
var f = corners[5];
var g = corners[6];
var h = corners[7];
// Get corners in current frame
this.getCorners(a, b, c, d, e, f, g, h);
// Transform them to new local frame
for(var i=0; i !== 8; i++){
var corner = corners[i];
frame.pointToWorld(corner, corner);
}
return target.setFromPoints(corners);
};
},{"../math/Vec3":30,"../utils/Utils":53}],4:[function(_dereq_,module,exports){
module.exports = ArrayCollisionMatrix;
/**
* Collision "matrix". It's actually a triangular-shaped array of whether two bodies are touching this step, for reference next step
* @class ArrayCollisionMatrix
* @constructor
*/
function ArrayCollisionMatrix() {
/**
* The matrix storage
* @property matrix
* @type {Array}
*/
this.matrix = [];
}
/**
* Get an element
* @method get
* @param {Number} i
* @param {Number} j
* @return {Number}
*/
ArrayCollisionMatrix.prototype.get = function(i, j) {
i = i.index;
j = j.index;
if (j > i) {
var temp = j;
j = i;
i = temp;
}
return this.matrix[(i*(i + 1)>>1) + j-1];
};
/**
* Set an element
* @method set
* @param {Number} i
* @param {Number} j
* @param {Number} value
*/
ArrayCollisionMatrix.prototype.set = function(i, j, value) {
i = i.index;
j = j.index;
if (j > i) {
var temp = j;
j = i;
i = temp;
}
this.matrix[(i*(i + 1)>>1) + j-1] = value ? 1 : 0;
};
/**
* Sets all elements to zero
* @method reset
*/
ArrayCollisionMatrix.prototype.reset = function() {
for (var i=0, l=this.matrix.length; i!==l; i++) {
this.matrix[i]=0;
}
};
/**
* Sets the max number of objects
* @method setNumObjects
* @param {Number} n
*/
ArrayCollisionMatrix.prototype.setNumObjects = function(n) {
this.matrix.length = n*(n-1)>>1;
};
},{}],5:[function(_dereq_,module,exports){
var Body = _dereq_('../objects/Body');
var Vec3 = _dereq_('../math/Vec3');
var Quaternion = _dereq_('../math/Quaternion');
_dereq_('../shapes/Shape');
_dereq_('../shapes/Plane');
module.exports = Broadphase;
/**
* Base class for broadphase implementations
* @class Broadphase
* @constructor
* @author schteppe
*/
function Broadphase(){
/**
* The world to search for collisions in.
* @property world
* @type {World}
*/
this.world = null;
/**
* If set to true, the broadphase uses bounding boxes for intersection test, else it uses bounding spheres.
* @property useBoundingBoxes
* @type {Boolean}
*/
this.useBoundingBoxes = false;
/**
* Set to true if the objects in the world moved.
* @property {Boolean} dirty
*/
this.dirty = true;
}
/**
* Get the collision pairs from the world
* @method collisionPairs
* @param {World} world The world to search in
* @param {Array} p1 Empty array to be filled with body objects
* @param {Array} p2 Empty array to be filled with body objects
*/
Broadphase.prototype.collisionPairs = function(world,p1,p2){
throw new Error("collisionPairs not implemented for this BroadPhase class!");
};
/**
* Check if a body pair needs to be intersection tested at all.
* @method needBroadphaseCollision
* @param {Body} bodyA
* @param {Body} bodyB
* @return {bool}
*/
var Broadphase_needBroadphaseCollision_STATIC_OR_KINEMATIC = Body.STATIC | Body.KINEMATIC;
Broadphase.prototype.needBroadphaseCollision = function(bodyA,bodyB){
// Check collision filter masks
if( (bodyA.collisionFilterGroup & bodyB.collisionFilterMask)===0 || (bodyB.collisionFilterGroup & bodyA.collisionFilterMask)===0){
return false;
}
// Check types
if(((bodyA.type & Broadphase_needBroadphaseCollision_STATIC_OR_KINEMATIC)!==0 || bodyA.sleepState === Body.SLEEPING) &&
((bodyB.type & Broadphase_needBroadphaseCollision_STATIC_OR_KINEMATIC)!==0 || bodyB.sleepState === Body.SLEEPING)) {
// Both bodies are static, kinematic or sleeping. Skip.
return false;
}
return true;
};
/**
* Check if the bounding volumes of two bodies intersect.
* @method intersectionTest
* @param {Body} bodyA
* @param {Body} bodyB
* @param {array} pairs1
* @param {array} pairs2
*/
Broadphase.prototype.intersectionTest = function(bodyA, bodyB, pairs1, pairs2){
if(this.useBoundingBoxes){
this.doBoundingBoxBroadphase(bodyA,bodyB,pairs1,pairs2);
} else {
this.doBoundingSphereBroadphase(bodyA,bodyB,pairs1,pairs2);
}
};
/**
* Check if the bounding spheres of two bodies are intersecting.
* @method doBoundingSphereBroadphase
* @param {Body} bodyA
* @param {Body} bodyB
* @param {Array} pairs1 bodyA is appended to this array if intersection
* @param {Array} pairs2 bodyB is appended to this array if intersection
*/
var Broadphase_collisionPairs_r = new Vec3(); // Temp objects
new Vec3();
new Quaternion();
new Vec3();
Broadphase.prototype.doBoundingSphereBroadphase = function(bodyA,bodyB,pairs1,pairs2){
var r = Broadphase_collisionPairs_r;
bodyB.position.vsub(bodyA.position,r);
var boundingRadiusSum2 = Math.pow(bodyA.boundingRadius + bodyB.boundingRadius, 2);
var norm2 = r.norm2();
if(norm2 < boundingRadiusSum2){
pairs1.push(bodyA);
pairs2.push(bodyB);
}
};
/**
* Check if the bounding boxes of two bodies are intersecting.
* @method doBoundingBoxBroadphase
* @param {Body} bodyA
* @param {Body} bodyB
* @param {Array} pairs1
* @param {Array} pairs2
*/
Broadphase.prototype.doBoundingBoxBroadphase = function(bodyA,bodyB,pairs1,pairs2){
if(bodyA.aabbNeedsUpdate){
bodyA.computeAABB();
}
if(bodyB.aabbNeedsUpdate){
bodyB.computeAABB();
}
// Check AABB / AABB
if(bodyA.aabb.overlaps(bodyB.aabb)){
pairs1.push(bodyA);
pairs2.push(bodyB);
}
};
/**
* Removes duplicate pairs from the pair arrays.
* @method makePairsUnique
* @param {Array} pairs1
* @param {Array} pairs2
*/
var Broadphase_makePairsUnique_temp = { keys:[] },
Broadphase_makePairsUnique_p1 = [],
Broadphase_makePairsUnique_p2 = [];
Broadphase.prototype.makePairsUnique = function(pairs1,pairs2){
var t = Broadphase_makePairsUnique_temp,
p1 = Broadphase_makePairsUnique_p1,
p2 = Broadphase_makePairsUnique_p2,
N = pairs1.length;
for(var i=0; i!==N; i++){
p1[i] = pairs1[i];
p2[i] = pairs2[i];
}
pairs1.length = 0;
pairs2.length = 0;
for(var i=0; i!==N; i++){
var id1 = p1[i].id,
id2 = p2[i].id;
var key = id1 < id2 ? id1+","+id2 : id2+","+id1;
t[key] = i;
t.keys.push(key);
}
for(var i=0; i!==t.keys.length; i++){
var key = t.keys.pop(),
pairIndex = t[key];
pairs1.push(p1[pairIndex]);
pairs2.push(p2[pairIndex]);
delete t[key];
}
};
/**
* To be implemented by subcasses
* @method setWorld
* @param {World} world
*/
Broadphase.prototype.setWorld = function(world){
};
/**
* Check if the bounding spheres of two bodies overlap.
* @method boundingSphereCheck
* @param {Body} bodyA
* @param {Body} bodyB
* @return {boolean}
*/
var bsc_dist = new Vec3();
Broadphase.boundingSphereCheck = function(bodyA,bodyB){
var dist = bsc_dist;
bodyA.position.vsub(bodyB.position,dist);
return Math.pow(bodyA.shape.boundingSphereRadius + bodyB.shape.boundingSphereRadius,2) > dist.norm2();
};
/**
* Returns all the bodies within the AABB.
* @method aabbQuery
* @param {World} world
* @param {AABB} aabb
* @param {array} result An array to store resulting bodies in.
* @return {array}
*/
Broadphase.prototype.aabbQuery = function(world, aabb, result){
console.warn('.aabbQuery is not implemented in this Broadphase subclass.');
return [];
};
},{"../math/Quaternion":28,"../math/Vec3":30,"../objects/Body":31,"../shapes/Plane":42,"../shapes/Shape":43}],6:[function(_dereq_,module,exports){
module.exports = GridBroadphase;
var Broadphase = _dereq_('./Broadphase');
var Vec3 = _dereq_('../math/Vec3');
var Shape = _dereq_('../shapes/Shape');
/**
* Axis aligned uniform grid broadphase.
* @class GridBroadphase
* @constructor
* @extends Broadphase
* @todo Needs support for more than just planes and spheres.
* @param {Vec3} aabbMin
* @param {Vec3} aabbMax
* @param {Number} nx Number of boxes along x
* @param {Number} ny Number of boxes along y
* @param {Number} nz Number of boxes along z
*/
function GridBroadphase(aabbMin,aabbMax,nx,ny,nz){
Broadphase.apply(this);
this.nx = nx || 10;
this.ny = ny || 10;
this.nz = nz || 10;
this.aabbMin = aabbMin || new Vec3(100,100,100);
this.aabbMax = aabbMax || new Vec3(-100,-100,-100);
var nbins = this.nx * this.ny * this.nz;
if (nbins <= 0) {
throw "GridBroadphase: Each dimension's n must be >0";
}
this.bins = [];
this.binLengths = []; //Rather than continually resizing arrays (thrashing the memory), just record length and allow them to grow
this.bins.length = nbins;
this.binLengths.length = nbins;
for (var i=0;i<nbins;i++) {
this.bins[i]=[];
this.binLengths[i]=0;
}
}
GridBroadphase.prototype = new Broadphase();
GridBroadphase.prototype.constructor = GridBroadphase;
/**
* Get all the collision pairs in the physics world
* @method collisionPairs
* @param {World} world
* @param {Array} pairs1
* @param {Array} pairs2
*/
var GridBroadphase_collisionPairs_d = new Vec3();
new Vec3();
GridBroadphase.prototype.collisionPairs = function(world,pairs1,pairs2){
var N = world.numObjects(),
bodies = world.bodies;
var max = this.aabbMax,
min = this.aabbMin,
nx = this.nx,
ny = this.ny,
nz = this.nz;
var xstep = ny*nz;
var ystep = nz;
var zstep = 1;
var xmax = max.x,
ymax = max.y,
zmax = max.z,
xmin = min.x,
ymin = min.y,
zmin = min.z;
var xmult = nx / (xmax-xmin),
ymult = ny / (ymax-ymin),
zmult = nz / (zmax-zmin);
var binsizeX = (xmax - xmin) / nx,
binsizeY = (ymax - ymin) / ny,
binsizeZ = (zmax - zmin) / nz;
var binRadius = Math.sqrt(binsizeX*binsizeX + binsizeY*binsizeY + binsizeZ*binsizeZ) * 0.5;
var types = Shape.types;
var SPHERE = types.SPHERE,
PLANE = types.PLANE;
types.BOX;
types.COMPOUND;
types.CONVEXPOLYHEDRON;
var bins=this.bins,
binLengths=this.binLengths,
Nbins=this.bins.length;
// Reset bins
for(var i=0; i!==Nbins; i++){
binLengths[i] = 0;
}
var ceil = Math.ceil;
var min = Math.min;
var max = Math.max;
function addBoxToBins(x0,y0,z0,x1,y1,z1,bi) {
var xoff0 = ((x0 - xmin) * xmult)|0,
yoff0 = ((y0 - ymin) * ymult)|0,
zoff0 = ((z0 - zmin) * zmult)|0,
xoff1 = ceil((x1 - xmin) * xmult),
yoff1 = ceil((y1 - ymin) * ymult),
zoff1 = ceil((z1 - zmin) * zmult);
if (xoff0 < 0) { xoff0 = 0; } else if (xoff0 >= nx) { xoff0 = nx - 1; }
if (yoff0 < 0) { yoff0 = 0; } else if (yoff0 >= ny) { yoff0 = ny - 1; }
if (zoff0 < 0) { zoff0 = 0; } else if (zoff0 >= nz) { zoff0 = nz - 1; }
if (xoff1 < 0) { xoff1 = 0; } else if (xoff1 >= nx) { xoff1 = nx - 1; }
if (yoff1 < 0) { yoff1 = 0; } else if (yoff1 >= ny) { yoff1 = ny - 1; }
if (zoff1 < 0) { zoff1 = 0; } else if (zoff1 >= nz) { zoff1 = nz - 1; }
xoff0 *= xstep;
yoff0 *= ystep;
zoff0 *= zstep;
xoff1 *= xstep;
yoff1 *= ystep;
zoff1 *= zstep;
for (var xoff = xoff0; xoff <= xoff1; xoff += xstep) {
for (var yoff = yoff0; yoff <= yoff1; yoff += ystep) {
for (var zoff = zoff0; zoff <= zoff1; zoff += zstep) {
var idx = xoff+yoff+zoff;
bins[idx][binLengths[idx]++] = bi;
}
}
}
}
// Put all bodies into the bins
for(var i=0; i!==N; i++){
var bi = bodies[i];
var si = bi.shape;
switch(si.type){
case SPHERE:
// Put in bin
// check if overlap with other bins
var x = bi.position.x,
y = bi.position.y,
z = bi.position.z;
var r = si.radius;
addBoxToBins(x-r, y-r, z-r, x+r, y+r, z+r, bi);
break;
case PLANE:
if(si.worldNormalNeedsUpdate){
si.computeWorldNormal(bi.quaternion);
}
var planeNormal = si.worldNormal;
//Relative position from origin of plane object to the first bin
//Incremented as we iterate through the bins
var xreset = xmin + binsizeX*0.5 - bi.position.x,
yreset = ymin + binsizeY*0.5 - bi.position.y,
zreset = zmin + binsizeZ*0.5 - bi.position.z;
var d = GridBroadphase_collisionPairs_d;
d.set(xreset, yreset, zreset);
for (var xi = 0, xoff = 0; xi !== nx; xi++, xoff += xstep, d.y = yreset, d.x += binsizeX) {
for (var yi = 0, yoff = 0; yi !== ny; yi++, yoff += ystep, d.z = zreset, d.y += binsizeY) {
for (var zi = 0, zoff = 0; zi !== nz; zi++, zoff += zstep, d.z += binsizeZ) {
if (d.dot(planeNormal) < binRadius) {
var idx = xoff + yoff + zoff;
bins[idx][binLengths[idx]++] = bi;
}
}
}
}
break;
default:
if (bi.aabbNeedsUpdate) {
bi.computeAABB();
}
addBoxToBins(
bi.aabb.lowerBound.x,
bi.aabb.lowerBound.y,
bi.aabb.lowerBound.z,
bi.aabb.upperBound.x,
bi.aabb.upperBound.y,
bi.aabb.upperBound.z,
bi);
break;
}
}
// Check each bin
for(var i=0; i!==Nbins; i++){
var binLength = binLengths[i];
//Skip bins with no potential collisions
if (binLength > 1) {
var bin = bins[i];
// Do N^2 broadphase inside
for(var xi=0; xi!==binLength; xi++){
var bi = bin[xi];
for(var yi=0; yi!==xi; yi++){
var bj = bin[yi];
if(this.needBroadphaseCollision(bi,bj)){
this.intersectionTest(bi,bj,pairs1,pairs2);
}
}
}
}
}
// for (var zi = 0, zoff=0; zi < nz; zi++, zoff+= zstep) {
// console.log("layer "+zi);
// for (var yi = 0, yoff=0; yi < ny; yi++, yoff += ystep) {
// var row = '';
// for (var xi = 0, xoff=0; xi < nx; xi++, xoff += xstep) {
// var idx = xoff + yoff + zoff;
// row += ' ' + binLengths[idx];
// }
// console.log(row);
// }
// }
this.makePairsUnique(pairs1,pairs2);
};
},{"../math/Vec3":30,"../shapes/Shape":43,"./Broadphase":5}],7:[function(_dereq_,module,exports){
module.exports = NaiveBroadphase;
var Broadphase = _dereq_('./Broadphase');
var AABB = _dereq_('./AABB');
/**
* Naive broadphase implementation, used in lack of better ones.
* @class NaiveBroadphase
* @constructor
* @description The naive broadphase looks at all possible pairs without restriction, therefore it has complexity N^2 (which is bad)
* @extends Broadphase
*/
function NaiveBroadphase(){
Broadphase.apply(this);
}
NaiveBroadphase.prototype = new Broadphase();
NaiveBroadphase.prototype.constructor = NaiveBroadphase;
/**
* Get all the collision pairs in the physics world
* @method collisionPairs
* @param {World} world
* @param {Array} pairs1
* @param {Array} pairs2
*/
NaiveBroadphase.prototype.collisionPairs = function(world,pairs1,pairs2){