.DS_Store
# Generated assets
-assets
+dist
+.cache
+
+# Personal config files
+.rgignore
- Pixi powered renderer system
- Matter-js powered physics system
- Scripts to setup hooks, linting, docs, and bundling
+- Keyboard Support
[Unreleased]: https://github.com/rbdr/sumo/compare/master...develop
super(config);
/**
- * The properthy that holds the pixi container
+ * The properthy that holds the angle
*
- * @property {external:MatterJs.Angle} angle
+ * @property {number} angle
* @instance
* @memberof AngleComponent
*/
super(config);
/**
- * The properthy that holds the pixi container
+ * The properthy that holds the matterjs body
*
* @property {external:MatterJs.Body} body
* @instance
--- /dev/null
+import { Component } from '@serpentity/serpentity';
+
+/**
+ * The contorl mapping object, holds a source and target for the action.
+ *
+ * @typedef tControlMap
+ * @type object
+ *
+ * @property {tControlSource} source the source input for the action
+ * @property {tControlTarget} target the target property for the action
+ */
+
+/**
+ * The definition of an input source
+ *
+ * @typedef tControlSource
+ * @type object
+ *
+ * @property {string} type type of input, can be keyboard or gamepad (only keyboard supported atm)
+ * @property {number} gamepadNumber the number of gamepad to use (unsupported)
+ * @property {string} gamepadInputSource either axes or buttons
+ * @property {number} index the input index or keycode
+ */
+
+/**
+ * The definition of an input target
+ *
+ * @typedef tControlTarget
+ * @type object
+ *
+ * @property {external:Serpentity:Component} component the component affected by this
+ * @property {string} property property to affect. For nested properties use dot.notation
+ * @property {[function]} value a function that takes in the input and outputs a transformed value
+ */
+
+/**
+ * Component that stores the state of motion controls to properties
+ *
+ * @extends {external:Serpentity.Component}
+ * @class ControlMapComponent
+ * @param {object} config a configuration object to extend.
+ */
+export default class ControlMapComponent extends Component {
+ constructor(config) {
+
+ super(config);
+
+ /**
+ * The map of actions and controls. An array of mappings
+ *
+ * @property {Array<tControlMap>} map
+ * @instance
+ * @memberof ControlMapComponent
+ */
+ this.map = this.map || [];
+ }
+};
--- /dev/null
+import { Component } from '@serpentity/serpentity';
+
+/**
+ * Component that stores a dash skill
+ *
+ * @extends {external:Serpentity.Component}
+ * @class DashComponent
+ * @param {object} config a configuration object to extend.
+ */
+export default class DashComponent extends Component {
+ constructor(config) {
+
+ super(config);
+
+ /**
+ * The properthy that holds the dash state
+ *
+ * @property {boolean} dashing
+ * @instance
+ * @memberof DashComponent
+ */
+ this.dashing = this.dashing || false;
+
+ /**
+ * Whether the dash is locked from occuring
+ *
+ * @property {boolean} locked
+ * @instance
+ * @memberof DashComponent
+ */
+ this.locked = this.locked || false;
+
+ /**
+ * Cooldown before lock is removed
+ *
+ * @property {number} cooldown
+ * @instance
+ * @memberof DashComponent
+ */
+ this.cooldown = this.cooldown || 4000;
+
+ /**
+ * Current cooldown
+ *
+ * @property {number} currentCooldown
+ * @instance
+ * @memberof DashComponent
+ */
+ this.currentCooldown = 0;
+ }
+};
--- /dev/null
+import { Component } from '@serpentity/serpentity';
+
+/**
+ * Component that stores elastic properties
+ *
+ * @extends {external:Serpentity.Component}
+ * @class ElasticComponent
+ * @param {object} config a configuration object to extend.
+ */
+export default class ElasticComponent extends Component {
+};
+
--- /dev/null
+import { Component } from '@serpentity/serpentity';
+
+/**
+ * Component that stores a force vector
+ *
+ * @extends {external:Serpentity.Component}
+ * @class ForceComponent
+ * @param {object} config a configuration object to extend.
+ */
+export default class ForceComponent extends Component {
+ constructor(config) {
+
+ super(config);
+
+ /**
+ * The properthy that holds the x component of the vector
+ *
+ * @property {number} x
+ * @instance
+ * @memberof AngleComponent
+ */
+ this.x = this.x || 0;
+
+ /**
+ * The properthy that holds the y component of the vector
+ *
+ * @property {number} y
+ * @instance
+ * @memberof AngleComponent
+ */
+
+ this.y = this.y || 0;
+ /**
+ * The properthy that holds the z component of the vector
+ *
+ * @property {number} z
+ * @instance
+ * @memberof AngleComponent
+ */
+ this.z = this.z || 0;
+ }
+};
+
--- /dev/null
+import { Component } from '@serpentity/serpentity';
+
+/**
+ * Component that stores max velocity constraint
+ *
+ * @extends {external:Serpentity.Component}
+ * @class MaxVelocityComponent
+ * @param {object} config a configuration object to extend.
+ */
+export default class MaxVelocityComponent extends Component {
+ constructor(config) {
+
+ super(config);
+
+ /**
+ * The properthy that holds the max velocity
+ *
+ * @property {number} maxVelocity
+ * @instance
+ * @memberof MaxVelocityComponent
+ */
+ this.maxVelocity = this.maxVelocity || 20;
+ }
+};
+
--- /dev/null
+/**
+ Changes the stiffness on the node when it's less extended
+ *
+ * @name Config
+ * @type object
+ */
+export default {
+
+ /**
+ * How many pixels to use per meter
+ *
+ * @property {number} meterSize
+ * @memberof Config
+ */
+ meterSize: 25
+};
createEmptyGraphic(config) {
return new Graphics();
+ },
+
+ /**
+ * Creates a harness graphic
+ *
+ * @function createHarness
+ * @memberof PixiFactory
+ * @return {external:CreateJs.Container} the created container
+ */
+ createHarness(config) {
+
+ const radius = config.radius;
+
+ const lineThickness = 10;
+
+ // The body
+ const body = new Graphics();
+ body.lineStyle(lineThickness, 0xe1e1e1, 1)
+ .drawCircle(0, 0, radius);
+
+ const center = new Graphics();
+ center.beginFill(0xf1f1f1)
+ .drawCircle(0, 0, radius - lineThickness / 2)
+ .endFill();
+
+ body.addChild(center);
+
+ return body;
}
};
import { Bodies, Constraint } from 'matter-js';
import { Entity } from '@serpentity/serpentity';
+// Components
+
import AngleComponent from '../components/angle';
import BodyComponent from '../components/body';
+import ControlMapComponent from '../components/control_map';
import CoupledEntitiesComponent from '../components/coupled_entities';
+import DashComponent from '../components/dash';
+import ElasticComponent from '../components/elastic';
+import ForceComponent from '../components/force';
+import MaxVelocityComponent from '../components/max_velocity';
import PositionComponent from '@serpentity/components.position';
import PixiContainerComponent from '../components/pixi_container';
+
import PixiFactory from '../factories/pixi';
+import Config from '../config';
const internals = {
kNoEntityError: 'Entity Not Found: This method requires entityA and entityB to be set in the config.',
entity.addComponent(new AngleComponent(config.angle));
const angle = entity.getComponent(AngleComponent);
+ entity.addComponent(new ForceComponent(config.force));
+
+ config.maxVelocity = {
+ maxVelocity: 12
+ };
+ entity.addComponent(new MaxVelocityComponent(config.maxVelocity));
+
+ // CONTROLS & ABILITIES
+
+ entity.addComponent(new DashComponent(config.dash));
+
// RENDERING
const radius = 25;
// PHYSICS
- const frictionAir = 0.00001;
- const friction = 0.00001;
+ const frictionAir = 0.02;
+ const friction = 1;
+ const frictionStatic = 1;
const restitution = 0.9;
- const density = 0.5;
+ const density = 1;
- const body = Bodies.circle(position.x, position.y, radius, {
+ const body = Bodies.circle(position.x / Config.meterSize, position.y / Config.meterSize, radius / Config.meterSize, {
+ label: 'Sumo body',
angle: angle.angle,
density,
frictionAir,
+ frictionStatic,
friction,
restitution
});
const bodyA = config.entityA.getComponent(BodyComponent).body;
const bodyB = config.entityB.getComponent(BodyComponent).body;
- const damping = 0.01;
- const length = 100;
- const stiffness = 0.0001;
- const angularStiffness = 0.0001;
+ const damping = 0;
+ const length = 100 / Config.meterSize;
+ const stiffness = 0.001;
const body = Constraint.create({
bodyA,
bodyB,
damping,
length,
- stiffness,
- angularStiffness
+ stiffness
});
entity.addComponent(new BodyComponent({ body }));
coupledEntities: [config.entityA, config.entityB]
}));
+ entity.addComponent(new ElasticComponent());
+
+ if (engine) {
+ engine.addEntity(entity);
+ }
+
+ return entity;
+ },
+
+ /**
+ * Creates a controllable sumo entity and adds it to the engine. Can override
+ * position in the config object
+ *
+ * @function createControllableSumo
+ * @memberof SumoFactory
+ * @param {external:Serpentity} [engine] the serpentity engine to attach
+ * to. If not sent, it will not be attached.
+ * @param {object} [config] the config to override the entity, accepts
+ * the key `position` as an object with an x and y property.
+ * @return {external:Serpentity.Entity} the created entity
+ */
+ createControllableSumo(engine, config = {}) {
+
+ const entity = this.createSumo(null, config);
+
+ entity.addComponent(new ControlMapComponent({
+ map: [
+ {
+ source: {
+ type: 'keyboard',
+ index: 37 // left arrow
+ },
+ target: {
+ component: ForceComponent,
+ property: 'x',
+ value: (value) => -Number(value)
+ }
+ },
+ {
+ source: {
+ type: 'keyboard',
+ index: 39 // right arrow
+ },
+ target: {
+ component: ForceComponent,
+ property: 'x',
+ value: (value) => Number(value)
+ }
+ },
+ {
+ source: {
+ type: 'keyboard',
+ index: 38 // up arrow
+ },
+ target: {
+ component: ForceComponent,
+ property: 'y',
+ value: (value) => -Number(value)
+ }
+ },
+ {
+ source: {
+ type: 'keyboard',
+ index: 40 // down arrow
+ },
+ target: {
+ component: ForceComponent,
+ property: 'y',
+ value: (value) => Number(value)
+ }
+ },
+ {
+ source: {
+ type: 'keyboard',
+ index: 90 // Z
+ },
+ target: {
+ component: DashComponent,
+ property: 'dashing'
+ }
+ }
+ ]
+ }));
+
+ if (engine) {
+ engine.addEntity(entity);
+ }
+
+ return entity;
+ },
+
+ /**
+ * Creates a static harness entity
+ *
+ * @function createHarness
+ * @memberof SumoFactory
+ * @param {external:Serpentity} [engine] the serpentity engine to attach
+ * to. If not sent, it will not be attached.
+ * @param {object} [config] the config to override the entity, accepts
+ * the key `position` as an object with an x and y property.
+ * @return {external:Serpentity.Entity} the created entity
+ */
+ createHarness(engine, config = {}) {
+
+ const entity = new Entity();
+
+ // POSITION
+
+ entity.addComponent(new PositionComponent(config.position));
+ const position = entity.getComponent(PositionComponent);
+
+ // RENDERING
+
+ const radius = 15;
+
+ const container = config.container || {
+ container: PixiFactory.createHarness({ radius })
+ };
+ container.container.position.x = position.x;
+ container.container.position.y = position.y;
+ entity.addComponent(new PixiContainerComponent(container));
+
+ // PHYSICS
+
+ const friction = 0;
+ const frictionStatic = 0;
+ const restitution = 1;
+
+ const body = Bodies.circle(position.x / Config.meterSize, position.y / Config.meterSize, radius / Config.meterSize, {
+ isStatic: true,
+ label: 'Harness body',
+ friction,
+ restitution,
+ frictionStatic
+ });
+ entity.addComponent(new BodyComponent({ body }));
+
if (engine) {
engine.addEntity(entity);
}
--- /dev/null
+import { Node } from '@serpentity/serpentity';
+
+import ControlMapComponent from '../components/control_map';
+
+/**
+ * Node identifying an entity that has a control mapping
+ *
+ * @extends {external:Serpentity.Node}
+ * @class ControllableNode
+ */
+export default class ControllableNode extends Node {
+
+};
+
+/**
+ * Holds the types that are used to identify a controllable entity
+ *
+ * @property {object} types
+ * @name types
+ * @memberof ControllableNode
+ */
+ControllableNode.types = {
+ controlMap: ControlMapComponent
+};
--- /dev/null
+import { Node } from '@serpentity/serpentity';
+
+import BodyComponent from '../components/body';
+import DashComponent from '../components/dash';
+import ForceComponent from '../components/force';
+
+/**
+ * Node identifying an entity that has a control mapping
+ *
+ * @extends {external:Serpentity.Node}
+ * @class DasherNode
+ */
+export default class DasherNode extends Node {
+
+};
+
+/**
+ * Holds the types that are used to identify a dasher entity
+ *
+ * @property {object} types
+ * @name types
+ * @memberof DasherNode
+ */
+DasherNode.types = {
+ body: BodyComponent,
+ dash: DashComponent,
+ force: ForceComponent
+};
+
--- /dev/null
+import { Node } from '@serpentity/serpentity';
+
+import BodyComponent from '../components/body';
+import ElasticComponent from '../components/elastic';
+
+/**
+ * Node identifying an entity that is an elastic physical body
+ *
+ * @extends {external:Serpentity.Node}
+ * @class ElasticNode
+ */
+export default class ElasticNode extends Node {
+
+};
+
+/**
+ * Holds the types that are used to identify an elastic entity
+ *
+ * @property {object} types
+ * @name types
+ * @memberof ElasticNode
+ */
+ElasticNode.types = {
+ body: BodyComponent,
+ elastic: ElasticComponent
+};
+
--- /dev/null
+import { Node } from '@serpentity/serpentity';
+
+import BodyComponent from '../components/body';
+import MaxVelocityComponent from '../components/max_velocity';
+
+/**
+ * Node identifying an entity that is a limited velocity physical body
+ *
+ * @extends {external:Serpentity.Node}
+ * @class LimitedVelocityNode
+ */
+export default class LimitedVelocityNode extends Node {
+
+};
+
+/**
+ * Holds the types that are used to identify a limited velocity entity
+ *
+ * @property {object} types
+ * @name types
+ * @memberof LimitedVelocityNode
+ */
+LimitedVelocityNode.types = {
+ body: BodyComponent,
+ maxVelocity: MaxVelocityComponent
+};
--- /dev/null
+import { Node } from '@serpentity/serpentity';
+
+import BodyComponent from '../components/body';
+import ForceComponent from '../components/force';
+
+/**
+ * Node identifying an entity that has externally applied force
+ *
+ * @extends {external:Serpentity.Node}
+ * @class PhysicalWithExternalForceNode
+ */
+export default class PhysicalWithExternalForceNode extends Node {
+
+};
+
+/**
+ * Holds the types that are used to identify an entity with a physical
+ * body
+ *
+ * @property {object} types
+ * @name types
+ * @memberof PhysicalWithExternalForceNode
+ */
+PhysicalWithExternalForceNode.types = {
+ body: BodyComponent,
+ force: ForceComponent
+};
import 'babel-polyfill';
+
+// Systems
+import ApplyForceSystem from './systems/apply_force';
+import CreateCouplingLineSystem from './systems/create_coupling_line';
+import ControlMapperSystem from './systems/control_mapper';
+import DashSystem from './systems/dash';
+import ElasticSystem from './systems/elastic';
import PhysicsWorldControlSystem from './systems/physics_world_control';
import PhysicsToAttributesSystem from './systems/physics_to_attributes';
-import CreateCouplingLineSystem from './systems/create_coupling_line';
import RenderSystem from './systems/render';
import AttributesToRenderableSystem from './systems/attributes_to_renderable';
+
+// Factories
+
import SumoFactory from './factories/sumo';
+
+// External Dependencies
+
import Serpentity from '@serpentity/serpentity';
import { Application } from 'pixi.js';
import { Engine } from 'matter-js';
// We're sending the currentTime since it gives better results for
// this type of renderer, though usually we expect the delta
- this._engine.update(currentTime);
+ this._engine.update(currentFrameDuration);
this._previousTime = currentTime;
}
}
_initializeSystems() {
+ this._engine.addSystem(new ControlMapperSystem());
+
+ this._engine.addSystem(new DashSystem());
+
+ this._engine.addSystem(new ApplyForceSystem());
+
this._engine.addSystem(new PhysicsWorldControlSystem({
engine: this._matterJs
}));
+ this._engine.addSystem(new ElasticSystem());
+
this._engine.addSystem(new PhysicsToAttributesSystem());
this._engine.addSystem(new AttributesToRenderableSystem());
_initializeEntities() {
- const entityA = SumoFactory.createSumo(null, {
+ const sumoA = SumoFactory.createSumo(null, {
position: {
x: 50,
y: 50
}
});
- const entityB = SumoFactory.createSumo(null, {
+ const sumoB = SumoFactory.createControllableSumo(null, {
position: {
- x: 309,
- y: 112
+ x: 500,
+ y: 78
}
});
- const entityC = SumoFactory.createSumo(null, {
+ const harness = SumoFactory.createHarness(null, {
position: {
- x: 500,
- y: 78
+ x: 309,
+ y: 112
}
});
SumoFactory.createRubberBand(this._engine, {
- entityA,
- entityB
+ entityA: sumoA,
+ entityB: harness
});
SumoFactory.createRubberBand(this._engine, {
- entityA: entityC,
- entityB
+ entityA: sumoB,
+ entityB: harness
});
// To keep the coupling behind, we'll manually add the sumos later
- this._engine.addEntity(entityA);
- this._engine.addEntity(entityB);
- this._engine.addEntity(entityC);
+ this._engine.addEntity(sumoA);
+ this._engine.addEntity(sumoB);
+ this._engine.addEntity(harness);
}
};
--- /dev/null
+import { System } from '@serpentity/serpentity';
+import { Body, Vector } from 'matter-js';
+
+const internals = {
+ kForce: 0.0001
+};
+
+import PhysicalWithExternalForceNode from '../nodes/physical_with_external_force';
+
+/**
+ * Applies physica from external forces (eg. controls) to the physics body
+ *
+ * @extends {external:Serpentity.System}
+ * @class ApplyForceSystem
+ * @param {object} config a configuration object to extend.
+ */
+export default class ApplyForceSystem extends System {
+
+ constructor(config = {}) {
+
+ super();
+
+ /**
+ * The node collection of entities that have external force
+ *
+ * @property {external:Serpentity.NodeCollection} physicalEntities
+ * @instance
+ * @memberof ApplyForceSystem
+ */
+ this.physicalEntities = null;
+ }
+
+ /**
+ * Initializes system when added. Requests physics nodes
+ *
+ * @function added
+ * @memberof ApplyForceSystem
+ * @instance
+ * @param {external:Serpentity.Engine} engine the serpentity engine to
+ * which we are getting added
+ */
+ added(engine) {
+
+ this.physicalEntities = engine.getNodes(PhysicalWithExternalForceNode);
+ }
+
+ /**
+ * Clears system resources when removed.
+ *
+ * @function removed
+ * @instance
+ * @memberof ApplyForceSystem
+ */
+ removed() {
+
+ this.physicalEntities = null;
+ }
+
+ /**
+ * Runs on every update of the loop. Updates the body based on the force
+ * component
+ *
+ * @function update
+ * @instance
+ * @param {Number} currentFrameDuration the duration of the current
+ * frame
+ * @memberof ApplyForceSystem
+ */
+ update(currentFrameDuration) {
+
+ for (const physicalEntity of this.physicalEntities) {
+ const body = physicalEntity.body.body;
+ const force = physicalEntity.force;
+ const forceVector = Vector.create(force.x * internals.kForce, force.y * internals.kForce);
+
+
+ // Store the last angle and apply force on non-zero forces
+
+ if (force.x || force.y) {
+ force.lastAngle = Math.atan2(force.y, force.x);
+ Body.applyForce(body,
+ {
+ x: body.position.x,
+ y: body.position.y
+ },
+ forceVector
+ );
+ }
+
+ // Reset the force
+
+ force.x = 0;
+ force.y = 0;
+ }
+ }
+};
+
--- /dev/null
+import { System } from '@serpentity/serpentity';
+
+import ControllableNode from '../nodes/controllable';
+
+/* global window */
+
+const internals = {
+ keyboardState: {
+ }
+};
+
+/**
+ * Updates control status based on the controller map
+ *
+ * @extends {external:Serpentity.System}
+ * @class ControlMapperSystem
+ * @param {object} config a configuration object to extend.
+ */
+export default class ControlMapperSystem extends System {
+
+ constructor(config = {}) {
+
+ super();
+
+ /**
+ * The node collection of controllable entities
+ *
+ * @property {external:Serpentity.NodeCollection} controllables
+ * @instance
+ * @memberof RenderSystem
+ */
+ this.controllables = null;
+
+ this._initializeKeyboard();
+ }
+
+ /**
+ * Initializes system when added. Requests controllable nodes.
+ *
+ * @function added
+ * @memberof RenderSystem
+ * @instance
+ * @param {external:Serpentity.Engine} engine the serpentity engine to
+ * which we are getting added
+ */
+ added(engine) {
+
+ this.controllables = engine.getNodes(ControllableNode);
+ }
+
+ /**
+ * Clears system resources when removed.
+ *
+ * @function removed
+ * @instance
+ * @memberof RenderSystem
+ */
+ removed() {
+
+ this.controllables = null;
+ }
+
+ /**
+ * Runs on every update of the loop. Maps the actions given the current state of the inputs
+ *
+ * @function update
+ * @instance
+ * @param {Number} currentFrameDuration the duration of the current
+ * frame
+ * @memberof RenderSystem
+ */
+ update(currentFrameDuration) {
+
+ for (const controllable of this.controllables) {
+ for (const map of controllable.controlMap.map) {
+ if (map.source.type === 'keyboard') {
+ this._setValue(controllable.entity, map.target, !!internals.keyboardState[map.source.index]);
+ }
+ }
+ }
+ }
+
+ // Listens to keyboard to update internal map
+
+ _initializeKeyboard() {
+
+ window.addEventListener('keydown', (event) => {
+
+ internals.keyboardState[event.keyCode] = true;
+ });
+
+ window.addEventListener('keyup', (event) => {
+
+ internals.keyboardState[event.keyCode] = false;
+ });
+ }
+
+ // Sets the value to a target
+
+ _setValue(entity, target, value) {
+
+ const component = entity.getComponent(target.component);
+
+ if (component) {
+ const keyFragments = target.property.split('.');
+ let currentObject = component;
+ for (const keyFragment of keyFragments.slice(0, keyFragments.length - 1)) {
+ currentObject = currentObject[keyFragment] = currentObject[keyFragment] || {};
+ }
+
+
+ const finalValue = !!target.value ? target.value(value) : value;
+ const finalProperty = keyFragments.pop();
+ currentObject[finalProperty] += finalValue;
+ }
+ }
+};
+
--- /dev/null
+import { System } from '@serpentity/serpentity';
+
+const internals = {
+ kForce: 10
+};
+
+import DasherNode from '../nodes/dasher';
+
+/**
+ * Applies a dash as a force on an entity. Locks it until the button is released
+ * and a cooldown period has passed
+ *
+ * @extends {external:Serpentity.System}
+ * @class DashSystem
+ * @param {object} config a configuration object to extend.
+ */
+export default class DashSystem extends System {
+
+ constructor(config = {}) {
+
+ super();
+
+ /**
+ * The node collection of dashers
+ *
+ * @property {external:Serpentity.NodeCollection} dashers
+ * @instance
+ * @memberof DashSystem
+ */
+ this.dashers = null;
+ }
+
+ /**
+ * Initializes system when added. Requests dasher nodes
+ *
+ * @function added
+ * @memberof DashSystem
+ * @instance
+ * @param {external:Serpentity.Engine} engine the serpentity engine to
+ * which we are getting added
+ */
+ added(engine) {
+
+ this.dashers = engine.getNodes(DasherNode);
+ }
+
+ /**
+ * Clears system resources when removed.
+ *
+ * @function removed
+ * @instance
+ * @memberof DashSystem
+ */
+ removed() {
+
+ this.dashers = null;
+ }
+
+ /**
+ * Runs on every update of the loop. Triggers dash and manages cooldown
+ *
+ * @function update
+ * @instance
+ * @param {Number} currentFrameDuration the duration of the current
+ * frame
+ * @memberof DashSystem
+ */
+ update(currentFrameDuration) {
+
+ for (const dasher of this.dashers) {
+
+ const dash = dasher.dash;
+
+ if (dash.dashing && !dash.locked) {
+ this._dash(dasher);
+ }
+
+ if (!dash.dashing && dash.locked && dash.currentCooldown >= dash.cooldown) {
+ this._unlock(dasher);
+ }
+
+ if (dash.locked) {
+ dash.currentCooldown += currentFrameDuration;
+ }
+
+ dash.dashing = 0;
+ }
+ }
+
+ // Executes the dash action
+
+ _dash(dasher) {
+
+ const dash = dasher.dash;
+ const force = dasher.force;
+
+ const angle = force.lastAngle || 0;
+ dash.locked = true;
+ dash.currentCooldown = 0;
+
+ const xComponent = internals.kForce * Math.cos(angle);
+ const yComponent = internals.kForce * Math.sin(angle);
+
+ force.x += xComponent;
+ force.y += yComponent;
+ }
+
+ // Executes the unlock action
+
+ _unlock(dasher) {
+
+ dasher.dash.locked = false;
+ }
+};
+
+
--- /dev/null
+import { System } from '@serpentity/serpentity';
+
+const internals = {
+ kTightStiffness: 0.001,
+ kBaseStiffness: 0.0008,
+ kLooseStiffness: 0.0000001
+};
+
+import ElasticNode from '../nodes/elastic';
+
+/**
+ Changes the stiffness on the node when it's less extended
+ *
+ * @extends {external:Serpentity.System}
+ * @class ElasticSystem
+ * @param {object} config a configuration object to extend.
+ */
+export default class ElasticSystem extends System {
+
+ constructor(config = {}) {
+
+ super();
+
+ /**
+ * The node collection of entities that have external force
+ *
+ * @property {external:Serpentity.NodeCollection} elastics
+ * @instance
+ * @memberof ElasticSystem
+ */
+ this.elastics = null;
+ }
+
+ /**
+ * Initializes system when added. Requests elastic nodes
+ *
+ * @function added
+ * @memberof ElasticSystem
+ * @instance
+ * @param {external:Serpentity.Engine} engine the serpentity engine to
+ * which we are getting added
+ */
+ added(engine) {
+
+ this.elastics = engine.getNodes(ElasticNode);
+ }
+
+ /**
+ * Clears system resources when removed.
+ *
+ * @function removed
+ * @instance
+ * @memberof ElasticSystem
+ */
+ removed() {
+
+ this.elastics = null;
+ }
+
+ /**
+ * Runs on every update of the loop. Checks length of elastic and adjusts
+ * stiffness
+ *
+ * @function update
+ * @instance
+ * @param {Number} currentFrameDuration the duration of the current
+ * frame
+ * @memberof ElasticSystem
+ */
+ update(currentFrameDuration) {
+
+ for (const elastic of this.elastics) {
+ const constraint = elastic.body.body;
+
+ const currentDistance = Math.abs(
+ Math.sqrt(
+ Math.pow(constraint.bodyA.position.x - constraint.bodyB.position.x, 2) +
+ Math.pow(constraint.bodyA.position.y - constraint.bodyB.position.y, 2)));
+
+ if (currentDistance <= constraint.length) {
+ constraint.stiffness = internals.kLooseStiffness;
+ continue;
+ }
+
+ if (currentDistance >= 2.6 * constraint.length) {
+ constraint.stiffness = internals.kTightStiffness;
+ continue;
+ }
+
+ constraint.stiffness = internals.kBaseStiffness;
+ }
+ }
+};
import { System } from '@serpentity/serpentity';
import PhysicalWithAttributesNode from '../nodes/physical_with_attributes';
+import Config from '../config';
/**
* Distribuets physics data to the related components
update(currentFrameDuration) {
for (const physicalEntity of this.physicalEntities) {
- physicalEntity.position.x = physicalEntity.body.body.position.x;
- physicalEntity.position.y = physicalEntity.body.body.position.y;
+ physicalEntity.position.x = physicalEntity.body.body.position.x * Config.meterSize;
+ physicalEntity.position.y = physicalEntity.body.body.position.y * Config.meterSize;
physicalEntity.angle.angle = physicalEntity.body.body.angle;
}
}
*/
update(currentFrameDuration) {
- Engine.run(this.engine);
+ Engine.update(this.engine, currentFrameDuration);
}
};
--- /dev/null
+import { System } from '@serpentity/serpentity';
+
+import LimitedVelocityNode from '../nodes/limited_velocity';
+
+/**
+ * Reduces velocity if it exceeds threshold
+ *
+ * @extends {external:Serpentity.System}
+ * @class ReduceVelocitySystem
+ * @param {object} config a configuration object to extend.
+ */
+export default class ReduceVelocitySystem extends System {
+
+ constructor(config = {}) {
+
+ super();
+
+ /**
+ * The node collection of entities that have external force
+ *
+ * @property {external:Serpentity.NodeCollection} limitedVelocityEntities
+ * @instance
+ * @memberof ReduceVelocitySystem
+ */
+ this.limitedVelocityEntities = null;
+ }
+
+ /**
+ * Initializes system when added. Requests limited velocity nodes
+ *
+ * @function added
+ * @memberof ReduceVelocitySystem
+ * @instance
+ * @param {external:Serpentity.Engine} engine the serpentity engine to
+ * which we are getting added
+ */
+ added(engine) {
+
+ this.limitedVelocityEntities = engine.getNodes(LimitedVelocityNode);
+ }
+
+ /**
+ * Clears system resources when removed.
+ *
+ * @function removed
+ * @instance
+ * @memberof ReduceVelocitySystem
+ */
+ removed() {
+
+ this.limitedVelocityEntities = null;
+ }
+
+ /**
+ * Runs on every update of the loop. Checks current velocity and adjusts if necessary
+ *
+ * @function update
+ * @instance
+ * @param {Number} currentFrameDuration the duration of the current
+ * frame
+ * @memberof ReduceVelocitySystem
+ */
+ update(currentFrameDuration) {
+
+ for (const limitedVelocityEntity of this.limitedVelocityEntities) {
+ console.log(limitedVelocityEntity.body.body.velocity, limitedVelocityEntity.maxVelocity.maxVelocity);
+ }
+ }
+};
+
/**
* The pixi engine we will use to render
*
- * @property {external:PixiJs.Application} renderables
+ * @property {external:PixiJs.Application} application
* @instance
* @memberof RenderSystem
*/
- this._application = config.application;
+ this.application = config.application;
- if (!this._application) {
+ if (!this.application) {
throw new Error(internals.kNoPixiError);
}
}
this.renderables = engine.getNodes(RenderableNode);
this.renderables.on('nodeAdded', (event) => {
- this._application.stage.addChild(event.node.container.container);
+ this.application.stage.addChild(event.node.container.container);
});
this.renderables.on('nodeRemoved', (event) => {
- this._application.stage.removeChild(event.node.container.container);
+ this.application.stage.removeChild(event.node.container.container);
});
}