UNPKG

p2s

Version:

A JavaScript 2D physics engine.

166 lines (137 loc) 4.7 kB
var TupleDictionary = require('./TupleDictionary'); var OverlapKeeperRecordPool = require('./OverlapKeeperRecordPool'); module.exports = OverlapKeeper; /** * Keeps track of overlaps in the current state and the last step state. * @class OverlapKeeper * @constructor */ function OverlapKeeper() { this.overlappingShapesLastState = new TupleDictionary(); this.overlappingShapesCurrentState = new TupleDictionary(); this.recordPool = new OverlapKeeperRecordPool({ size: 16 }); this.tmpDict = new TupleDictionary(); this.tmpArray1 = []; } /** * Ticks one step forward in time. This will move the current overlap state to the "old" overlap state, and create a new one as current. * @method tick */ OverlapKeeper.prototype.tick = function() { var last = this.overlappingShapesLastState; var current = this.overlappingShapesCurrentState; // Save old objects into pool var l = last.keys.length; while(l--){ var key = last.keys[l]; var lastObject = last.getByKey(key); if(lastObject){ // The record is only used in the "last" dict, and will be removed. We might as well pool it. this.recordPool.release(lastObject); } } // Clear last object last.reset(); // Transfer from new object to old last.copy(current); // Clear current object current.reset(); }; /** * @method setOverlapping * @param {Body} bodyA * @param {Body} shapeA * @param {Body} bodyB * @param {Body} shapeB */ OverlapKeeper.prototype.setOverlapping = function(bodyA, shapeA, bodyB, shapeB) { var current = this.overlappingShapesCurrentState; // Store current contact state if(!current.get(shapeA.id, shapeB.id)){ var data = this.recordPool.get(); data.set(bodyA, shapeA, bodyB, shapeB); current.set(shapeA.id, shapeB.id, data); } }; OverlapKeeper.prototype.getNewOverlaps = function(result){ return this.getDiff(this.overlappingShapesLastState, this.overlappingShapesCurrentState, result); }; OverlapKeeper.prototype.getEndOverlaps = function(result){ return this.getDiff(this.overlappingShapesCurrentState, this.overlappingShapesLastState, result); }; /** * Checks if two bodies are currently overlapping. * @method bodiesAreOverlapping * @param {Body} bodyA * @param {Body} bodyB * @return {boolean} */ OverlapKeeper.prototype.bodiesAreOverlapping = function(bodyA, bodyB){ var current = this.overlappingShapesCurrentState; var l = current.keys.length; while(l--){ var key = current.keys[l]; var data = current.data[key]; if((data.bodyA === bodyA && data.bodyB === bodyB) || data.bodyA === bodyB && data.bodyB === bodyA){ return true; } } return false; }; OverlapKeeper.prototype.getDiff = function(dictA, dictB, result){ var result = result || []; var last = dictA; var current = dictB; result.length = 0; var l = current.keys.length; while(l--){ var key = current.keys[l]; var data = current.data[key]; if(!data){ throw new Error('Key '+key+' had no data!'); } var lastData = last.data[key]; if(!lastData){ // Not overlapping in last state, but in current. result.push(data); } } return result; }; OverlapKeeper.prototype.isNewOverlap = function(shapeA, shapeB){ var idA = shapeA.id|0, idB = shapeB.id|0; var last = this.overlappingShapesLastState; var current = this.overlappingShapesCurrentState; // Not in last but in new return !!!last.get(idA, idB) && !!current.get(idA, idB); }; OverlapKeeper.prototype.getNewBodyOverlaps = function(result){ this.tmpArray1.length = 0; var overlaps = this.getNewOverlaps(this.tmpArray1); return this.getBodyDiff(overlaps, result); }; OverlapKeeper.prototype.getEndBodyOverlaps = function(result){ this.tmpArray1.length = 0; var overlaps = this.getEndOverlaps(this.tmpArray1); return this.getBodyDiff(overlaps, result); }; OverlapKeeper.prototype.getBodyDiff = function(overlaps, result){ result = result || []; var accumulator = this.tmpDict; var l = overlaps.length; while(l--){ var data = overlaps[l]; // Since we use body id's for the accumulator, these will be a subset of the original one accumulator.set(data.bodyA.id|0, data.bodyB.id|0, data); } l = accumulator.keys.length; while(l--){ var data = accumulator.getByKey(accumulator.keys[l]); if(data){ result.push(data.bodyA, data.bodyB); } } accumulator.reset(); return result; };