* @instance
* @memberof DashComponent
*/
- this.cooldown = this.cooldown || 4000;
+ this.cooldown = this.cooldown || 3000;
/**
* Current cooldown
* @name Config
* @type object
*/
-export default {
+const config = {
/**
* How many pixels to use per meter
* @property {number} meterSize
* @memberof Config
*/
- meterSize: 25
+ meterSize: 25,
+
+ /**
+ * Aspect Ratio the aspect ratio expressed as an array of two numbers
+ *
+ * @property {number} aspectRatio
+ * @memberof Config
+ */
+ aspectRatio: [2.76, 1],
+
+ /**
+ * Target vertical resolution
+ *
+ * @property {number} verticalResolution
+ * @memberof Config
+ */
+ verticalResolution: 224
+
};
+
+/**
+ * How many pixels to use per meter
+ *
+ * @property {number} meterSize
+ * @memberof Config
+ */
+config.horizontalResolution = Math.round(config.verticalResolution * config.aspectRatio[0] / config.aspectRatio[1]);
+
+export default config;
.endFill();
// The mouth
- const mouth = new Graphics();
- mouth.lineStyle(10, 0xff0080, 1)
+ const smile = new Graphics();
+ smile.name = 'smile';
+ smile.lineStyle(10, 0xff0080, 1)
.arc(
0, 0, // center
radius * 0.6,
5 * Math.PI / 6
);
+ const frown = new Graphics();
+ frown.name = 'frown';
+ frown.visible = false;
+ frown.lineStyle(10, 0xff0080, 1)
+ .arc(
+ 0, radius,
+ radius * 0.6,
+ -Math.PI / 5,
+ -4 * Math.PI / 5,
+ true
+ );
+
const leftEye = new Graphics();
leftEye.beginFill(0xffffff)
.drawCircle(-radius / 3 - radius / 8, -radius / 4, radius / 5)
leftPupil.beginFill(0x11)
.drawCircle(radius / 3 + radius / 8, -radius / 4, radius / 10);
+ body.addChild(this.createBlush({ radius }));
+
// The group
- body.addChild(mouth);
+ body.addChild(smile);
+ body.addChild(frown);
body.addChild(leftEye);
body.addChild(rightEye);
body.addChild(leftPupil);
body.addChild(center);
return body;
+ },
+
+ /**
+ * Creates an arena graphic
+ *
+ * @function createArena
+ * @memberof PixiFactory
+ * @return {external:CreateJs.Container} the created container
+ */
+ createArena(config) {
+
+ const radius = config.radius;
+
+ const lineThickness = 20;
+
+ // The body
+ const arena = new Graphics();
+ arena.lineStyle(lineThickness, 0xdfd4b2, 1)
+ .drawCircle(0, 0, radius);
+
+ const leftLine = new Graphics();
+ leftLine.lineStyle(20, 0xbdb08b, 1)
+ .moveTo(-radius / 4, -radius / 8)
+ .lineTo(-radius / 4, radius / 8);
+
+ const rightLine = new Graphics();
+ rightLine.lineStyle(20, 0xbdb08b, 1)
+ .moveTo(radius / 4, -radius / 8)
+ .lineTo(radius / 4, radius / 8);
+
+ arena.addChild(leftLine);
+ arena.addChild(rightLine);
+
+ return arena;
+ },
+
+ /**
+ * Creates a blush for the face
+ *
+ * @function createBlush
+ * @memberof PixiFactory
+ * @return {external:CreateJs.Container} the created container
+ */
+ createBlush(config) {
+
+ const radius = config.radius;
+
+ const blush = new Graphics();
+
+ blush.name = 'blush';
+ blush.visible = false;
+
+ const leftEyebrow = new Graphics();
+ leftEyebrow.lineStyle(4, 0x11, 1)
+ .arc(
+ -radius / 3 - radius / 4, -radius / 2 - radius / 4,
+ radius / 3,
+ Math.PI / 8,
+ 2 * Math.PI / 3
+ );
+
+ const leftBlush = new Graphics();
+ leftBlush.lineStyle(4, 0xe7bfe6, 1)
+ .moveTo(-radius / 3 - radius / 4, radius / 10)
+ .lineTo(-radius / 3, 0);
+
+ const rightEyebrow = new Graphics();
+ rightEyebrow.lineStyle(4, 0x11, 1)
+ .arc(
+ radius / 3 + radius / 4, -radius / 2 - radius / 4,
+ radius / 3,
+ Math.PI / 3,
+ 7 * Math.PI / 8
+ );
+
+ const rightBlush = new Graphics();
+ rightBlush.lineStyle(4, 0xe7bfe6, 1)
+ .moveTo(radius / 3 + radius / 4, radius / 10)
+ .lineTo(radius / 3, 0);
+
+ blush.addChild(leftEyebrow);
+ blush.addChild(leftBlush);
+ blush.addChild(rightEyebrow);
+ blush.addChild(rightBlush);
+
+ return blush;
}
};
-
const frictionAir = 0.02;
const friction = 1;
const frictionStatic = 1;
- const restitution = 0.9;
- const density = 1;
+ const restitution = 1;
+ const density = 1.5;
const body = Bodies.circle(position.x / Config.meterSize, position.y / Config.meterSize, radius / Config.meterSize, {
label: 'Sumo body',
engine.addEntity(entity);
}
+ return entity;
+ },
+
+ /**
+ * Creates a static arena entity
+ *
+ * @function createArena
+ * @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
+ */
+ createArena(engine, config = {}) {
+
+ const entity = new Entity();
+
+ // POSITION
+
+ entity.addComponent(new PositionComponent(config.position));
+ const position = entity.getComponent(PositionComponent);
+
+ // RENDERING
+
+ const radius = 300;
+
+ const container = config.container || {
+ container: PixiFactory.createArena({ radius })
+ };
+ container.container.position.x = position.x;
+ container.container.position.y = position.y;
+ entity.addComponent(new PixiContainerComponent(container));
+
+ if (engine) {
+ engine.addEntity(entity);
+ }
+
return entity;
}
};
--- /dev/null
+import { Node } from '@serpentity/serpentity';
+
+import DashComponent from '../components/dash';
+import PixiContainerComponent from '../components/pixi_container';
+
+/**
+ * Node identifying an entity that can dash and is drawn
+ *
+ * @extends {external:Serpentity.Node}
+ * @class DrawnDasherNode
+ */
+export default class DrawnDasherNode extends Node {
+
+};
+
+/**
+ * Holds the types that are used to identify a drawn dasher entity
+ *
+ * @property {object} types
+ * @name types
+ * @memberof DrawnDasherNode
+ */
+DrawnDasherNode.types = {
+ container: PixiContainerComponent,
+ dash: DashComponent
+};
+
import 'babel-polyfill';
+import Config from './config';
+
// 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 DrawDashSystem from './systems/draw_dash';
import ElasticSystem from './systems/elastic';
import PhysicsWorldControlSystem from './systems/physics_world_control';
import PhysicsToAttributesSystem from './systems/physics_to_attributes';
onLoad() {
- const sumo = new internals.Sumo({
+ const sumo = new internals.Sumo(Object.assign({
element: document.getElementById('sumo-app-entry-point')
- });
+ }, Config));
sumo.startLoop();
- internals.exports.sumo = sumo;
+ window.sumo = sumo;
}
};
constructor(config) {
+ // These defaults can get overridden by config
this.fps = 60;
this.aspectRatio = [2.76, 1];
this.verticalResolution = 224;
this._engine.addSystem(new CreateCouplingLineSystem());
+ this._engine.addSystem(new DrawDashSystem());
+
this._engine.addSystem(new RenderSystem({
application: this._pixi
}));
_initializeEntities() {
+ SumoFactory.createArena(this._engine, {
+ position: {
+ x: this.horizontalResolution / 2,
+ y: this.verticalResolution / 2
+ }
+ });
+
const sumoA = SumoFactory.createSumo(null, {
position: {
- x: 50,
- y: 50
+ x: this.horizontalResolution / 2 - 100,
+ y: this.verticalResolution / 2
}
});
const sumoB = SumoFactory.createControllableSumo(null, {
position: {
- x: 500,
- y: 78
+ x: this.horizontalResolution / 2 + 100,
+ y: this.verticalResolution / 2
}
});
const harness = SumoFactory.createHarness(null, {
position: {
- x: 309,
- y: 112
+ x: this.horizontalResolution / 2,
+ y: this.verticalResolution / 2
}
});
import { System } from '@serpentity/serpentity';
const internals = {
- kForce: 10
+ kForce: 20
};
import DasherNode from '../nodes/dasher';
--- /dev/null
+import { System } from '@serpentity/serpentity';
+
+import DrawnDasherNode from '../nodes/drawn_dasher';
+
+const internals = {
+ kBlushRadius: 25
+};
+
+/**
+ * Shows a different graphic during the duration of lock
+ *
+ * @extends {external:Serpentity.System}
+ * @class DrawDashSystem
+ * @param {object} config a configuration object to extend.
+ */
+export default class DrawDashSystem extends System {
+
+ constructor(config = {}) {
+
+ super();
+
+ /**
+ * The node collection of dashers
+ *
+ * @property {external:Serpentity.NodeCollection} drawnDashers
+ * @instance
+ * @memberof DrawDashSystem
+ */
+ this.drawnDashers = null;
+ }
+
+ /**
+ * Initializes system when added. Requests drawn dasher nodes
+ *
+ * @function added
+ * @memberof DrawDashSystem
+ * @instance
+ * @param {external:Serpentity.Engine} engine the serpentity engine to
+ * which we are getting added
+ */
+ added(engine) {
+
+ this.drawnDashers = engine.getNodes(DrawnDasherNode);
+ }
+
+ /**
+ * Clears system resources when removed.
+ *
+ * @function removed
+ * @instance
+ * @memberof DrawDashSystem
+ */
+ removed() {
+
+ this.drawnDashers = null;
+ }
+
+ /**
+ * Runs on every update of the loop. Updates image depending on if
+ * dash is locked
+ *
+ * @function update
+ * @instance
+ * @param {Number} currentFrameDuration the duration of the current
+ * frame
+ * @memberof DrawDashSystem
+ */
+ update(currentFrameDuration) {
+
+ for (const drawnDasher of this.drawnDashers) {
+
+ const dash = drawnDasher.dash;
+ const container = drawnDasher.container.container;
+
+ if (dash.locked) {
+ this._drawDashFace(container);
+ continue;
+ }
+
+ this._removeDashFace(container);
+ }
+ }
+
+ // Draws the dash face
+
+ _drawDashFace(container) {
+
+ const blush = container.getChildByName('blush');
+ const smile = container.getChildByName('smile');
+ const frown = container.getChildByName('frown');
+ blush.visible = true;
+ frown.visible = true;
+ smile.visible = false;
+ }
+
+ // Removes the dash face
+
+ _removeDashFace(container) {
+
+ const blush = container.getChildByName('blush');
+ const smile = container.getChildByName('smile');
+ const frown = container.getChildByName('frown');
+ blush.visible = false;
+ frown.visible = false;
+ smile.visible = true;
+ }
+};
* frame
* @memberof RenderSystem
*/
- update(currentFrameDuration) {}
+ update(currentFrameDuration) {
+
+ this.application.render();
+ }
};