From: Rubén Beltrán del Río Date: Mon, 23 Apr 2018 12:58:20 +0000 (-0500) Subject: Draw the Arena (#7) X-Git-Url: https://git.r.bdr.sh/rbdr/sumo/commitdiff_plain/6768cd461ec1a8ea87c0f64e1b3c29e36b0b02ed?ds=sidebyside;hp=7ade6f8d96825386bf2e89dea51f9297cbac8e9c Draw the Arena (#7) * Add defaults to config * Create arena sprite * Draw the arena * Draw a face when cooling down the dash * Correct linter issues --- diff --git a/lib/components/dash.js b/lib/components/dash.js index de1fe2c..77807ef 100644 --- a/lib/components/dash.js +++ b/lib/components/dash.js @@ -37,7 +37,7 @@ export default class DashComponent extends Component { * @instance * @memberof DashComponent */ - this.cooldown = this.cooldown || 4000; + this.cooldown = this.cooldown || 3000; /** * Current cooldown diff --git a/lib/config.js b/lib/config.js index ba02ed8..856fc18 100644 --- a/lib/config.js +++ b/lib/config.js @@ -4,7 +4,7 @@ * @name Config * @type object */ -export default { +const config = { /** * How many pixels to use per meter @@ -12,5 +12,32 @@ export default { * @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; diff --git a/lib/factories/pixi.js b/lib/factories/pixi.js index 839e593..786639f 100644 --- a/lib/factories/pixi.js +++ b/lib/factories/pixi.js @@ -27,8 +27,9 @@ export default { .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, @@ -36,6 +37,18 @@ export default { 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) @@ -53,8 +66,11 @@ export default { 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); @@ -101,6 +117,91 @@ export default { 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; } }; - diff --git a/lib/factories/sumo.js b/lib/factories/sumo.js index ea5a71c..dad9987 100644 --- a/lib/factories/sumo.js +++ b/lib/factories/sumo.js @@ -82,8 +82,8 @@ export default { 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', @@ -296,6 +296,44 @@ export default { 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; } }; diff --git a/lib/nodes/drawn_dasher.js b/lib/nodes/drawn_dasher.js new file mode 100644 index 0000000..162593f --- /dev/null +++ b/lib/nodes/drawn_dasher.js @@ -0,0 +1,27 @@ +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 +}; + diff --git a/lib/sumo.js b/lib/sumo.js index 2b6f085..eef80d7 100644 --- a/lib/sumo.js +++ b/lib/sumo.js @@ -1,10 +1,14 @@ 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'; @@ -31,13 +35,13 @@ const internals = { 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; } }; @@ -61,6 +65,7 @@ internals.Sumo = class Sumo { constructor(config) { + // These defaults can get overridden by config this.fps = 60; this.aspectRatio = [2.76, 1]; this.verticalResolution = 224; @@ -206,6 +211,8 @@ internals.Sumo = class Sumo { this._engine.addSystem(new CreateCouplingLineSystem()); + this._engine.addSystem(new DrawDashSystem()); + this._engine.addSystem(new RenderSystem({ application: this._pixi })); @@ -215,24 +222,31 @@ internals.Sumo = class Sumo { _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 } }); diff --git a/lib/systems/dash.js b/lib/systems/dash.js index d05e9ea..f648d36 100644 --- a/lib/systems/dash.js +++ b/lib/systems/dash.js @@ -1,7 +1,7 @@ import { System } from '@serpentity/serpentity'; const internals = { - kForce: 10 + kForce: 20 }; import DasherNode from '../nodes/dasher'; diff --git a/lib/systems/draw_dash.js b/lib/systems/draw_dash.js new file mode 100644 index 0000000..118ce1c --- /dev/null +++ b/lib/systems/draw_dash.js @@ -0,0 +1,107 @@ +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; + } +}; diff --git a/lib/systems/render.js b/lib/systems/render.js index 06d0e60..83c740d 100644 --- a/lib/systems/render.js +++ b/lib/systems/render.js @@ -88,5 +88,8 @@ export default class RenderSystem extends System { * frame * @memberof RenderSystem */ - update(currentFrameDuration) {} + update(currentFrameDuration) { + + this.application.render(); + } };