UNPKG

planck-js

Version:

2D physics engine for JavaScript/HTML5 game development

227 lines (195 loc) 6.71 kB
/* * 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; }