diff options
Diffstat (limited to 'lib/systems/grab.js')
| -rw-r--r-- | lib/systems/grab.js | 183 |
1 files changed, 183 insertions, 0 deletions
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; + } +}; |