aboutsummaryrefslogtreecommitdiff
path: root/lib/systems
diff options
context:
space:
mode:
Diffstat (limited to 'lib/systems')
-rw-r--r--lib/systems/draw_dash.js4
-rw-r--r--lib/systems/draw_grab.js115
-rw-r--r--lib/systems/grab.js183
-rw-r--r--lib/systems/physics_world_control.js17
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 {
}
};
-