planck-js
Version:
2D physics engine for JavaScript/HTML5 game development
227 lines (195 loc) • 6.71 kB
JavaScript
/*
* Copyright (c) 2016 Ali Shakiba http://shakiba.me/planck.js
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
var Settings = require('../Settings');
var Math = require('../common/Math');
var AABB = require('./AABB');
var DynamicTree = require('./DynamicTree');
module.exports = BroadPhase;
/**
* The broad-phase wraps and extends a dynamic-tree keep to track of moved
* objects and query them on update.
*/
function BroadPhase() {
this.m_tree = new DynamicTree();
this.m_proxyCount = 0;
this.m_moveBuffer = [];
};
/**
* Get user data from a proxy. Returns null if the id is invalid.
*/
BroadPhase.prototype.GetUserData = function(proxyId) {
return this.m_tree.GetUserData(proxyId);
}
/**
* Test overlap of fat AABBs.
*/
BroadPhase.prototype.TestOverlap = function(proxyIdA, proxyIdB) {
var aabbA = this.m_tree.GetFatAABB(proxyIdA);
var aabbB = this.m_tree.GetFatAABB(proxyIdB);
return AABB.TestOverlap(aabbA, aabbB);
}
/**
* Get the fat AABB for a proxy.
*/
BroadPhase.prototype.GetFatAABB = function(proxyId) {
return this.m_tree.GetFatAABB(proxyId);
}
/**
* Get the number of proxies.
*/
BroadPhase.prototype.GetProxyCount = function() {
return this.m_proxyCount;
}
/**
* Get the height of the embedded tree.
*/
BroadPhase.prototype.GetTreeHeight = function() {
return this.m_tree.GetHeight();
}
/**
* Get the balance (integer) of the embedded tree.
*/
BroadPhase.prototype.GetTreeBalance = function() {
return this.m_tree.GetMaxBalance();
}
/**
* Get the quality metric of the embedded tree.
*/
BroadPhase.prototype.GetTreeQuality = function() {
return this.m_tree.GetAreaRatio();
}
/**
* Query an AABB for overlapping proxies. The callback class is called for each
* proxy that overlaps the supplied AABB.
*/
BroadPhase.prototype.Query = function(callback, aabb) {
this.m_tree.Query(callback, aabb);
}
/**
* Ray-cast against the proxies in the tree. This relies on the callback to
* perform a exact ray-cast in the case were the proxy contains a shape. The
* callback also performs the any collision filtering. This has performance
* roughly equal to k * log(n), where k is the number of collisions and n is the
* number of proxies in the tree.
*
* @param callback A callback class that is called for each proxy that is hit by
* the ray.
* @param input The ray-cast input data. The ray extends from p1 to p1 +
* maxFraction * (p2 - p1).
*/
BroadPhase.prototype.RayCast = function(callback, input) {
this.m_tree.RayCast(callback, input);
}
/**
* Shift the world origin. Useful for large worlds. The shift formula is:
* position -= newOrigin
*
* @param newOrigin The new origin with respect to the old origin
*/
BroadPhase.prototype.ShiftOrigin = function(newOrigin) {
this.m_tree.ShiftOrigin(newOrigin);
}
/**
* Create a proxy with an initial AABB. Pairs are not reported until UpdatePairs
* is called.
*/
BroadPhase.prototype.CreateProxy = function(aabb, userData) {
Assert(AABB.IsValid(aabb));
var proxyId = this.m_tree.CreateProxy(aabb, userData);
this.m_proxyCount++;
this.BufferMove(proxyId);
return proxyId;
}
/**
* Destroy a proxy. It is up to the client to remove any pairs.
*/
BroadPhase.prototype.DestroyProxy = function(proxyId) {
this.UnBufferMove(proxyId);
this.m_proxyCount--;
this.m_tree.DestroyProxy(proxyId);
}
/**
* Call MoveProxy as many times as you like, then when you are done call
* UpdatePairs to finalized the proxy pairs (for your time step).
*/
BroadPhase.prototype.MoveProxy = function(proxyId, aabb, displacement) {
Assert(AABB.IsValid(aabb));
var changed = this.m_tree.MoveProxy(proxyId, aabb, displacement);
if (changed) {
this.BufferMove(proxyId);
}
}
/**
* Call to trigger a re-processing of it's pairs on the next call to
* UpdatePairs.
*/
BroadPhase.prototype.TouchProxy = function(proxyId) {
this.BufferMove(proxyId);
}
BroadPhase.prototype.BufferMove = function(proxyId) {
this.m_moveBuffer.push(proxyId);
}
BroadPhase.prototype.UnBufferMove = function(proxyId) {
for (var i = 0; i < this.m_moveBuffer.length; ++i) {
if (this.m_moveBuffer[i] == proxyId) {
this.m_moveBuffer[i] = null;
}
}
}
/**
* @function BroadPhase~AddPair
* @param {Object} userDataA
* @param {Object} userDataB
*/
/**
* Update the pairs. This results in pair callbacks. This can only add pairs.
*
* @param {BroadPhase~AddPair} callback.AddPair
*/
BroadPhase.prototype.UpdatePairs = function(callback) {
this.m_callback = callback;
// Perform tree queries for all moving proxies.
while (this.m_moveBuffer.length > 0) {
this.m_queryProxyId = this.m_moveBuffer.pop();
if (this.m_queryProxyId === null) {
continue;
}
// We have to query the tree with the fat AABB so that
// we don't fail to create a pair that may touch later.
var fatAABB = this.m_tree.GetFatAABB(this.m_queryProxyId);
// Query tree, create pairs and add them pair buffer.
this.m_tree.Query(this, fatAABB);
}
// Try to keep the tree balanced.
// this.m_tree.Rebalance(4);
}
BroadPhase.prototype.QueryCallback = function(proxyId) {
// A proxy cannot form a pair with itself.
if (proxyId == this.m_queryProxyId) {
return true;
}
var proxyIdA = Math.min(proxyId, this.m_queryProxyId);
var proxyIdB = Math.max(proxyId, this.m_queryProxyId);
// TODO: Skip any duplicate pairs.
var userDataA = this.m_tree.GetUserData(proxyIdA);
var userDataB = this.m_tree.GetUserData(proxyIdB);
// Send the pairs back to the client.
this.m_callback.AddPair(userDataA, userDataB);
return true;
}