From b253683cb52fbe84f7b8466375b282857cfe6e58 Mon Sep 17 00:00:00 2001 From: liabru Date: Mon, 24 Mar 2014 19:48:23 +0000 Subject: [PATCH] composites now support removals (implemented isModified flag) --- src/body/Composite.js | 163 +++++++++++++++++++++++++++++++++++++----- src/collision/Grid.js | 2 +- src/core/Engine.js | 40 +++++++---- src/render/Gui.js | 7 +- src/render/Render.js | 10 +++ 5 files changed, 187 insertions(+), 35 deletions(-) diff --git a/src/body/Composite.js b/src/body/Composite.js index 59187e0..d0b1409 100644 --- a/src/body/Composite.js +++ b/src/body/Composite.js @@ -11,6 +11,8 @@ var Composite = {}; (function() { + var _nextId = 0; + /** * Description * @method create @@ -19,12 +21,49 @@ var Composite = {}; */ Composite.create = function(options) { return Common.extend({ + id: Composite.nextId(), + parent: null, + isModified: false, bodies: [], constraints: [], composites: [] }, options); }; + /** + * Returns the next unique compositeID + * @method nextId + * @return {Number} Unique compositeID + */ + Composite.nextId = function() { + return _nextId++; + }; + + /** + * Sets the composite's `isModified` flag. + * If `updateParents` is true, all parents will be set (default: false). + * If `updateChildren` is true, all children will be set (default: false). + * @method setModified + * @param {composite} composite + * @param {boolean} isModified + * @param {boolean} updateParents + * @param {boolean} updateChildren + */ + Composite.setModified = function(composite, isModified, updateParents, updateChildren) { + composite.isModified = isModified; + + if (updateParents && composite.parent) { + Composite.setModified(composite.parent, isModified, updateParents, updateChildren); + } + + if (updateChildren) { + for(var i = 0; i < composite.composites.length; i++) { + var childComposite = composite.composites[i]; + Composite.setModified(childComposite, isModified, updateParents, updateChildren); + } + } + }; + /** * Description * @method addComposite @@ -34,6 +73,8 @@ var Composite = {}; */ Composite.addComposite = function(compositeA, compositeB) { compositeA.composites.push(compositeB); + compositeB.parent = compositeA; + Composite.setModified(compositeA, true, true, false); return compositeA; }; @@ -46,6 +87,44 @@ var Composite = {}; */ Composite.addBody = function(composite, body) { composite.bodies.push(body); + Composite.setModified(composite, true, true, false); + return composite; + }; + + /** + * Removes a body from the given composite, and optionally searching its children recursively + * @method removeBody + * @param {composite} composite + * @param {body} body + * @param {boolean} deep + * @return {composite} The original composite with the body removed + */ + Composite.removeBody = function(composite, body, deep) { + var position = composite.bodies.indexOf(body); + if (position !== -1) { + Composite.removeBodyAt(composite, position); + Composite.setModified(composite, true, true, false); + } + + if (deep) { + for (var i = 0; i < composite.composites.length; i++){ + Composite.removeBody(composite.composites[i], body, true); + } + } + + return composite; + }; + + /** + * Removes a body from the given composite + * @method removeBodyAt + * @param {composite} composite + * @param {number} position + * @return {composite} The original composite with the body removed + */ + Composite.removeBodyAt = function(composite, position) { + composite.bodies.splice(position, 1); + Composite.setModified(composite, true, true, false); return composite; }; @@ -58,6 +137,71 @@ var Composite = {}; */ Composite.addConstraint = function(composite, constraint) { composite.constraints.push(constraint); + Composite.setModified(composite, true, true, false); + return composite; + }; + + /** + * Removes a constraint from the given composite, and optionally searching its children recursively + * @method removeConstraint + * @param {composite} composite + * @param {constraint} constraint + * @param {boolean} deep + * @return {composite} The original composite with the constraint removed + */ + Composite.removeConstraint = function(composite, constraint, deep) { + var position = composite.constraints.indexOf(constraint); + if (position !== -1) { + Composite.removeConstraintAt(composite, position); + } + + if (deep) { + for (var i = 0; i < composite.composites.length; i++){ + Composite.removeConstraint(composite.composites[i], constraint, true); + } + } + + return composite; + }; + + /** + * Removes a body from the given composite + * @method removeConstraintAt + * @param {composite} composite + * @param {number} position + * @return {composite} The original composite with the constraint removed + */ + Composite.removeConstraintAt = function(composite, position) { + composite.constraints.splice(position, 1); + Composite.setModified(composite, true, true, false); + return composite; + }; + + /** + * Removes all bodies, constraints and composites from the given composite + * Optionally clearing its children recursively + * @method clear + * @param {world} world + * @param {boolean} keepStatic + * @param {boolean} deep + */ + Composite.clear = function(composite, keepStatic, deep) { + if (deep) { + for (var i = 0; i < composite.composites.length; i++){ + Composite.clear(composite.composites[i], keepStatic, true); + } + } + + if (keepStatic) { + composite.bodies = composite.bodies.filter(function(body) { return body.isStatic; }); + } else { + composite.bodies.length = 0; + } + + composite.constraints.length = 0; + composite.composites.length = 0; + Composite.setModified(composite, true, true, false); + return composite; }; @@ -91,23 +235,4 @@ var Composite = {}; return constraints; }; - /** - * Removes all bodies, constraints and composites from the given composite (non-recursive) - * @method clear - * @param {world} world - * @param {boolean} keepStatic - */ - Composite.clear = function(composite, keepStatic) { - if (keepStatic) { - composite.bodies = composite.bodies.filter(function(body) { return body.isStatic; }); - } else { - composite.bodies.length = 0; - } - - composite.constraints.length = 0; - composite.composites.length = 0; - - return composite; - }; - })(); \ No newline at end of file diff --git a/src/collision/Grid.js b/src/collision/Grid.js index 7e1ff46..72c83f2 100644 --- a/src/collision/Grid.js +++ b/src/collision/Grid.js @@ -48,7 +48,7 @@ var Grid = {}; for (i = 0; i < bodies.length; i++) { var body = bodies[i]; - if (body.isSleeping) + if (body.isSleeping && !forceUpdate) continue; // don't update out of world bodies diff --git a/src/core/Engine.js b/src/core/Engine.js index c211823..1327f09 100644 --- a/src/core/Engine.js +++ b/src/core/Engine.js @@ -167,6 +167,10 @@ var Engine = {}; */ Events.trigger(engine, 'tick beforeUpdate', event); + // if world has been modified, clear the render scene graph + if (engine.world.isModified) + engine.render.controller.clear(engine.render); + // update Engine.update(engine, delta, correction); @@ -234,18 +238,24 @@ var Engine = {}; broadphasePairs = [], i; + // get lists of all bodies and constraints, no matter what composites they are in var allBodies = Composite.allBodies(world), allConstraints = Composite.allConstraints(world); + // reset metrics logging Metrics.reset(engine.metrics); + // if sleeping enabled, call the sleeping controller if (engine.enableSleeping) Sleeping.update(allBodies); + // applies gravity to all bodies Body.applyGravityAll(allBodies, world.gravity); + // update the mouse constraint MouseConstraint.update(engine.mouseConstraint, allBodies, engine.input); + // update all body position and rotation by integration Body.updateAll(allBodies, delta * engine.timeScale, correction, world.bounds); // update all constraints @@ -255,16 +265,24 @@ var Engine = {}; // broadphase pass: find potential collision pairs if (broadphase.controller) { - broadphase.controller.update(broadphase.instance, allBodies, engine); + + // if world is dirty, we must flush the whole grid + if (world.isModified) + broadphase.controller.clear(broadphase.instance); + + // update the grid buckets based on current bodies + broadphase.controller.update(broadphase.instance, allBodies, engine, world.isModified); broadphasePairs = broadphase.instance.pairsList; } else { + + // if no broadphase set, we just pass all bodies broadphasePairs = allBodies; } // narrowphase pass: find actual collisions, then create or update collision pairs var collisions = broadphase.detector(broadphasePairs, engine); - // update pairs + // update collision pairs var pairs = engine.pairs, timestamp = engine.timing.timestamp; Pairs.update(pairs, collisions, timestamp); @@ -286,11 +304,16 @@ var Engine = {}; } Resolver.postSolvePosition(allBodies); + // update metrics log Metrics.update(engine.metrics, engine); // clear force buffers Body.resetForcesAll(allBodies); + // clear all composite modified flags + if (world.isModified) + Composite.setModified(world, false, false, true); + return engine; }; @@ -315,14 +338,6 @@ var Engine = {}; Sleeping.set(body, false); body.id = Body.nextId(); } - - var broadphase = engineA.broadphase[engineA.broadphase.current]; - - if (broadphase.controller === Grid) { - var grid = broadphase.instance; - Grid.clear(grid); - Grid.update(grid, bodies, engineA, true); - } } }; @@ -339,12 +354,9 @@ var Engine = {}; World.addConstraint(engine.world, engine.mouseConstraint.constraint); var broadphase = engine.broadphase[engine.broadphase.current]; - - if (broadphase.controller === Grid) - Grid.clear(broadphase.instance); - if (broadphase.controller) { var bodies = Composite.allBodies(world); + broadphase.controller.clear(broadphase.instance); broadphase.controller.update(broadphase.instance, bodies, engine, true); } }; diff --git a/src/render/Gui.js b/src/render/Gui.js index 5c6f225..9a80431 100644 --- a/src/render/Gui.js +++ b/src/render/Gui.js @@ -132,7 +132,12 @@ var Gui = {}; var physics = datGui.addFolder('Engine'); physics.add(engine, 'enableSleeping'); - physics.add(engine.broadphase, 'current', ['grid', 'bruteForce']); + + physics.add(engine.broadphase, 'current', ['grid', 'bruteForce']) + .onFinishChange(function(value) { + Composite.setModified(engine.world, true, false, false); + }); + physics.add(engine, 'timeScale', 0.1, 2).step(0.1); physics.add(engine, 'velocityIterations', 1, 10).step(1); physics.add(engine, 'positionIterations', 1, 10).step(1); diff --git a/src/render/Render.js b/src/render/Render.js index 7c73c75..ef10c4e 100644 --- a/src/render/Render.js +++ b/src/render/Render.js @@ -61,6 +61,16 @@ var Render = {}; return render; }; + /** + * Clears the renderer. In this implementation, this is a noop. + * @method clear + * @param {RenderPixi} render + */ + Render.clear = function(render) { + // nothing required to clear this renderer implentation + // if a scene graph is required, clear it here (see RenderPixi.js) + }; + /** * Sets the background CSS property of the canvas * @method setBackground