API Docs for: 0.6.1
Show:

File: src/collision/SAPBroadphase.js

var Shape = require('../shapes/Shape');
var Broadphase = require('../collision/Broadphase');
module.exports = SAPBroadphase;
/**
 * Sweep and prune broadphase along one axis.
 *
 * @class SAPBroadphase
 * @constructor
 * @param {World} [world]
 * @extends Broadphase
 */
function SAPBroadphase(world){
 Broadphase.apply(this);
 /**
 * List of bodies currently in the broadphase.
 * @property axisList
 * @type {Array}
 */
 this.axisList = [];
 /**
 * The world to search in.
 * @property world
 * @type {World}
 */
 this.world = null;
 /**
 * Axis to sort the bodies along. Set to 0 for x axis, and 1 for y axis. For best performance, choose an axis that the bodies are spread out more on.
 * @property axisIndex
 * @type {Number}
 */
 this.axisIndex = 0;
 var axisList = this.axisList;
 this._addBodyHandler = function(e){
 axisList.push(e.body);
 };
 this._removeBodyHandler = function(e){
 var idx = axisList.indexOf(e.body);
 if(idx !== -1){
 axisList.splice(idx,1);
 }
 };
 if(world){
 this.setWorld(world);
 }
}
SAPBroadphase.prototype = new Broadphase();
/**
 * Change the world
 * @method setWorld
 * @param {World} world
 */
SAPBroadphase.prototype.setWorld = function(world){
 // Clear the old axis array
 this.axisList.length = 0;
 // Add all bodies from the new world
 for(var i=0; i<world.bodies.length; i++){
 this.axisList.push(world.bodies[i]);
 }
 // Remove old handlers, if any
 world.removeEventListener("addBody", this._addBodyHandler);
 world.removeEventListener("removeBody", this._removeBodyHandler);
 // Add handlers to update the list of bodies.
 world.addEventListener("addBody", this._addBodyHandler);
 world.addEventListener("removeBody", this._removeBodyHandler);
 this.world = world;
 this.dirty = true;
};
/**
 * @static
 * @method insertionSortX
 * @param {Array} a
 * @return {Array}
 */
SAPBroadphase.insertionSortX = function(a) {
 for(var i=1,l=a.length;i<l;i++) {
 var v = a[i];
 for(var j=i - 1;j>=0;j--) {
 if(a[j].aabb.lowerBound.x <= v.aabb.lowerBound.x){
 break;
 }
 a[j+1] = a[j];
 }
 a[j+1] = v;
 }
 return a;
};
/**
 * @static
 * @method insertionSortY
 * @param {Array} a
 * @return {Array}
 */
SAPBroadphase.insertionSortY = function(a) {
 for(var i=1,l=a.length;i<l;i++) {
 var v = a[i];
 for(var j=i - 1;j>=0;j--) {
 if(a[j].aabb.lowerBound.y <= v.aabb.lowerBound.y){
 break;
 }
 a[j+1] = a[j];
 }
 a[j+1] = v;
 }
 return a;
};
/**
 * @static
 * @method insertionSortZ
 * @param {Array} a
 * @return {Array}
 */
SAPBroadphase.insertionSortZ = function(a) {
 for(var i=1,l=a.length;i<l;i++) {
 var v = a[i];
 for(var j=i - 1;j>=0;j--) {
 if(a[j].aabb.lowerBound.z <= v.aabb.lowerBound.z){
 break;
 }
 a[j+1] = a[j];
 }
 a[j+1] = v;
 }
 return a;
};
/**
 * Collect all collision pairs
 * @method collisionPairs
 * @param {World} world
 * @param {Array} p1
 * @param {Array} p2
 */
SAPBroadphase.prototype.collisionPairs = function(world,p1,p2){
 var bodies = this.axisList,
 N = bodies.length,
 axisIndex = this.axisIndex,
 i, j;
 if(this.dirty){
 this.sortList();
 this.dirty = false;
 }
 // Look through the list
 for(i=0; i !== N; i++){
 var bi = bodies[i];
 for(j=i+1; j < N; j++){
 var bj = bodies[j];
 if(!this.needBroadphaseCollision(bi,bj)){
 continue;
 }
 if(!SAPBroadphase.checkBounds(bi,bj,axisIndex)){
 break;
 }
 this.intersectionTest(bi,bj,p1,p2);
 }
 }
};
SAPBroadphase.prototype.sortList = function(){
 var axisList = this.axisList;
 var axisIndex = this.axisIndex;
 var N = axisList.length;
 // Update AABBs
 for(var i = 0; i!==N; i++){
 var bi = axisList[i];
 if(bi.aabbNeedsUpdate){
 bi.computeAABB();
 }
 }
 // Sort the list
 if(axisIndex === 0){
 SAPBroadphase.insertionSortX(axisList);
 } else if(axisIndex === 1){
 SAPBroadphase.insertionSortY(axisList);
 } else if(axisIndex === 2){
 SAPBroadphase.insertionSortZ(axisList);
 }
};
/**
 * Check if the bounds of two bodies overlap, along the given SAP axis.
 * @static
 * @method checkBounds
 * @param {Body} bi
 * @param {Body} bj
 * @param {Number} axisIndex
 * @return {Boolean}
 */
SAPBroadphase.checkBounds = function(bi, bj, axisIndex){
 var biPos;
 var bjPos;
 if(axisIndex === 0){
 biPos = bi.position.x;
 bjPos = bj.position.x;
 } else if(axisIndex === 1){
 biPos = bi.position.y;
 bjPos = bj.position.y;
 } else if(axisIndex === 2){
 biPos = bi.position.z;
 bjPos = bj.position.z;
 }
 var ri = bi.boundingRadius,
 rj = bj.boundingRadius,
 boundA1 = biPos - ri,
 boundA2 = biPos + ri,
 boundB1 = bjPos - rj,
 boundB2 = bjPos + rj;
 return boundB1 < boundA2;
};
/**
 * Computes the variance of the body positions and estimates the best
 * axis to use. Will automatically set property .axisIndex.
 * @method autoDetectAxis
 */
SAPBroadphase.prototype.autoDetectAxis = function(){
 var sumX=0,
 sumX2=0,
 sumY=0,
 sumY2=0,
 sumZ=0,
 sumZ2=0,
 bodies = this.axisList,
 N = bodies.length,
 invN=1/N;
 for(var i=0; i!==N; i++){
 var b = bodies[i];
 var centerX = b.position.x;
 sumX += centerX;
 sumX2 += centerX*centerX;
 var centerY = b.position.y;
 sumY += centerY;
 sumY2 += centerY*centerY;
 var centerZ = b.position.z;
 sumZ += centerZ;
 sumZ2 += centerZ*centerZ;
 }
 var varianceX = sumX2 - sumX*sumX*invN,
 varianceY = sumY2 - sumY*sumY*invN,
 varianceZ = sumZ2 - sumZ*sumZ*invN;
 if(varianceX > varianceY){
 if(varianceX > varianceZ){
 this.axisIndex = 0;
 } else{
 this.axisIndex = 2;
 }
 } else if(varianceY > varianceZ){
 this.axisIndex = 1;
 } else{
 this.axisIndex = 2;
 }
};
/**
 * Returns all the bodies within an AABB.
 * @method aabbQuery
 * @param {World} world
 * @param {AABB} aabb
 * @param {array} result An array to store resulting bodies in.
 * @return {array}
 */
SAPBroadphase.prototype.aabbQuery = function(world, aabb, result){
 result = result || [];
 if(this.dirty){
 this.sortList();
 this.dirty = false;
 }
 var axisIndex = this.axisIndex, axis = 'x';
 if(axisIndex === 1){ axis = 'y'; }
 if(axisIndex === 2){ axis = 'z'; }
 var axisList = this.axisList;
 var lower = aabb.lowerBound[axis];
 var upper = aabb.upperBound[axis];
 for(var i = 0; i < axisList.length; i++){
 var b = axisList[i];
 if(b.aabbNeedsUpdate){
 b.computeAABB();
 }
 if(b.aabb.overlaps(aabb)){
 result.push(b);
 }
 }
 return result;
};
 

AltStyle によって変換されたページ (->オリジナル) /