diff options
| author | Rubén Beltrán del Río <ben@nsovocal.com> | 2018-05-28 21:35:38 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-05-28 21:35:38 -0500 |
| commit | 1676911c8a2621274bf75ff7271faa926cf58d6c (patch) | |
| tree | 776613e919a5fae242ba65f0871028d4c678bcff /lib/systems | |
| parent | 764ac76aa90b75cd5d79c217220654a6975069af (diff) | |
Add Grab System (#9)
* Remove unused code
* Adds grab components
* Adds grab nodes
* Add sensors to the physics world
* Add grab systems
* Add new sprites
* Attach grab components
* Add grab system to engine
* Update changelog
Diffstat (limited to 'lib/systems')
| -rw-r--r-- | lib/systems/draw_dash.js | 4 | ||||
| -rw-r--r-- | lib/systems/draw_grab.js | 115 | ||||
| -rw-r--r-- | lib/systems/grab.js | 183 | ||||
| -rw-r--r-- | lib/systems/physics_world_control.js | 17 |
4 files changed, 314 insertions, 5 deletions
diff --git a/lib/systems/draw_dash.js b/lib/systems/draw_dash.js index 118ce1c..5ce9043 100644 --- a/lib/systems/draw_dash.js +++ b/lib/systems/draw_dash.js @@ -2,10 +2,6 @@ import { System } from '@serpentity/serpentity'; import DrawnDasherNode from '../nodes/drawn_dasher'; -const internals = { - kBlushRadius: 25 -}; - /** * Shows a different graphic during the duration of lock * diff --git a/lib/systems/draw_grab.js b/lib/systems/draw_grab.js new file mode 100644 index 0000000..21ffdcd --- /dev/null +++ b/lib/systems/draw_grab.js @@ -0,0 +1,115 @@ +import { System } from '@serpentity/serpentity'; + +import DrawnGrabberNode from '../nodes/drawn_grabber'; + +/** + * Shows a different graphic during the duration of lock + * + * @extends {external:Serpentity.System} + * @class DrawGrabSystem + * @param {object} config a configuration object to extend. + */ +export default class DrawGrabSystem extends System { + + constructor(config = {}) { + + super(); + + /** + * The node collection of grabbers + * + * @property {external:Serpentity.NodeCollection} drawnGrabbers + * @instance + * @memberof DrawGrabSystem + */ + this.drawnGrabbers = null; + } + + /** + * Initializes system when added. Requests drawn grabber nodes + * + * @function added + * @memberof DrawGrabSystem + * @instance + * @param {external:Serpentity.Engine} engine the serpentity engine to + * which we are getting added + */ + added(engine) { + + this.drawnGrabbers = engine.getNodes(DrawnGrabberNode); + } + + /** + * Clears system resources when removed. + * + * @function removed + * @instance + * @memberof DrawGrabSystem + */ + removed() { + + this.drawnGrabbers = null; + } + + /** + * Runs on every update of the loop. Updates image depending on if + * grab is locked and active + * + * @function update + * @instance + * @param {Number} currentFrameDuration the duration of the current + * frame + * @memberof DrawGrabSystem + */ + update(currentFrameDuration) { + + for (const drawnGrabber of this.drawnGrabbers) { + + const grab = drawnGrabber.grab; + const container = drawnGrabber.container.container; + + if (grab.locked && grab.constraint) { + this._drawGrabFace(container); + continue; + } + + if (grab.locked) { + this._drawGrabCooldownFace(container); + continue; + } + + this._removeGrabFace(container); + } + } + + // Draws the grab face + + _drawGrabFace(container) { + + const effort = container.getChildByName('effort'); + const shadow = container.getChildByName('shadow'); + effort.visible = true; + shadow.visible = false; + } + + // Draws the grab cooldown face + + _drawGrabCooldownFace(container) { + + const effort = container.getChildByName('effort'); + const shadow = container.getChildByName('shadow'); + effort.visible = false; + shadow.visible = true; + } + + // Removes the dash face + + _removeGrabFace(container) { + + const effort = container.getChildByName('effort'); + const shadow = container.getChildByName('shadow'); + effort.visible = false; + shadow.visible = false; + } +}; + diff --git a/lib/systems/grab.js b/lib/systems/grab.js new file mode 100644 index 0000000..43e6246 --- /dev/null +++ b/lib/systems/grab.js @@ -0,0 +1,183 @@ +import { System } from '@serpentity/serpentity'; +import { Body, Constraint, SAT, World } from 'matter-js'; + +import GrabberNode from '../nodes/grabber'; +import GrabbableNode from '../nodes/grabbable'; + +import Config from '../config'; + +const internals = { + kGrabRadius: 50, + kNoEngine: 'No matter js physics engine found. Make sure you set the `engine` key in the config object when initializing.' +}; + +/** + * Handles grabbing between entities + * + * @extends {external:Serpentity.System} + * @class GrabSystem + * @param {object} config a configuration object to extend. + */ +export default class GrabSystem extends System { + + constructor(config = {}) { + + super(); + + /** + * The node collection of grabbers + * + * @property {external:Serpentity.NodeCollection} grabbers + * @instance + * @memberof GrabSystem + */ + this.grabbers = null; + + /** + * The node collection of grabbables + * + * @property {external:Serpentity.NodeCollection} grabbables + * @instance + * @memberof GrabSystem + */ + this.grabbables = null; + + /** + * The matter-js engine we will use to add and remove constraints + * + * @property {external:MatterJs.Engine} engine + * @instance + * @memberof GrabSystem + */ + this.engine = config.engine; + + if (!this.engine) { + throw new Error(internals.kNoEngine); + } + } + + /** + * Initializes system when added. Requests grabber and grabbable nodes + * + * @function added + * @memberof GrabSystem + * @instance + * @param {external:Serpentity.Engine} engine the serpentity engine to + * which we are getting added + */ + added(engine) { + + this.grabbers = engine.getNodes(GrabberNode); + this.grabbables = engine.getNodes(GrabbableNode); + } + + /** + * Clears system resources when removed. + * + * @function removed + * @instance + * @memberof GrabSystem + */ + removed() { + + this.grabbers = null; + this.grabbables = null; + } + + /** + * Runs on every update of the loop. Triggers grab and manages cooldown + * + * @function update + * @instance + * @param {Number} currentFrameDuration the duration of the current + * frame + * @memberof GrabSystem + */ + update(currentFrameDuration) { + + for (const grabber of this.grabbers) { + + const grab = grabber.grab; + + if (grab.grabbing && !grab.locked) { + this._grab(grabber); + } + + const isGrabReleased = !grab.grabbing || grab.currentCooldown >= grab.cooldown; + if (grab.constraint && isGrabReleased) { + this._release(grabber); + } + + if (!grab.grabbing && grab.locked && grab.currentCooldown >= grab.cooldown) { + this._unlock(grabber); + } + + if (grab.locked) { + grab.currentCooldown += currentFrameDuration; + } + + grab.grabbing = 0; + } + } + + // Executes the dash action + + _grab(grabber) { + + const grab = grabber.grab; + + grab.locked = true; + grab.currentCooldown = 0; + + Body.setPosition(grabber.grabArea.area, grabber.body.body.position); + + console.log('Grab!'); + + for (const grabbable of this.grabbables) { + + if (grabbable.entity === grabber.entity) { + continue; + } + + const collision = SAT.collides(grabber.grabArea.area, grabbable.body.body); + if (collision.collided) { + grab.constraint = this._createConstraint(grabber.body.body, grabbable.body.body); + console.log('Grabbing', grab.constraint); + } + } + } + + // Executes the unlock action + + _unlock(grabber) { + + grabber.grab.locked = false; + } + + // Releases a constraint + + _release(grabber) { + + console.log('Releasing', grabber.grab.constraint); + World.remove(this.engine.world, grabber.grab.constraint); + grabber.grab.currentCooldown = 0; + grabber.grab.constraint = null; + } + + // Performs a grab between two entities + + _createConstraint(grabber, grabbable) { + + const constraint = Constraint.create({ // Attach the sensor to the body + bodyA: grabber, + bodyB: grabbable, + damping: 0, + length: internals.kGrabRadius / Config.meterSize, + stiffness: 1 + }); + + World.add(this.engine.world, [constraint]); + + return constraint; + } +}; diff --git a/lib/systems/physics_world_control.js b/lib/systems/physics_world_control.js index a658d5c..370701e 100644 --- a/lib/systems/physics_world_control.js +++ b/lib/systems/physics_world_control.js @@ -2,6 +2,7 @@ import { System } from '@serpentity/serpentity'; import { Engine, World } from 'matter-js'; import PhysicalNode from '../nodes/physical'; +import GrabAreaNode from '../nodes/grab_area'; const internals = { kNoEngine: 'No matter js physics engine found. Make sure you set the `engine` key in the config object when initializing.' @@ -56,6 +57,8 @@ export default class PhysicsWorldControlSystem extends System { added(engine) { this.physicalEntities = engine.getNodes(PhysicalNode); + this.grabAreaEntities = engine.getNodes(GrabAreaNode); + this.physicalEntities.on('nodeAdded', (event) => { World.add(this.engine.world, [event.node.body.body]); @@ -64,6 +67,15 @@ export default class PhysicsWorldControlSystem extends System { World.remove(this.engine.world, [event.node.body.body]); }); + + this.grabAreaEntities.on('nodeAdded', (event) => { + + World.add(this.engine.world, [event.node.grabArea.area]); + }); + this.grabAreaEntities.on('nodeRemoved', (event) => { + + World.remove(this.engine.world, [event.node.grabArea.area]); + }); } /** @@ -78,6 +90,10 @@ export default class PhysicsWorldControlSystem extends System { this.physicalEntities.removeAllListeners('nodeAdded'); this.physicalEntities.removeAllListeners('nodeRemoved'); this.physicalEntities = null; + + this.grabAreaEntities.removeAllListeners('nodeAdded'); + this.grabAreaEntities.removeAllListeners('nodeRemoved'); + this.grabAreaEntities = null; } /** @@ -95,4 +111,3 @@ export default class PhysicsWorldControlSystem extends System { } }; - |