X-Git-Url: https://git.r.bdr.sh/rbdr/sumo/blobdiff_plain/7ade6f8d96825386bf2e89dea51f9297cbac8e9c..bb8d5ef47baf7ad16a1bc58526f81ce332b090d6:/lib/factories/sumo.js?ds=sidebyside diff --git a/lib/factories/sumo.js b/lib/factories/sumo.js index ea5a71c..009ba8c 100644 --- a/lib/factories/sumo.js +++ b/lib/factories/sumo.js @@ -10,9 +10,15 @@ import CoupledEntitiesComponent from '../components/coupled_entities'; import DashComponent from '../components/dash'; import ElasticComponent from '../components/elastic'; import ForceComponent from '../components/force'; +import GrabAreaComponent from '../components/grab_area'; +import GrabbableComponent from '../components/grabbable'; +import GrabComponent from '../components/grab'; import MaxVelocityComponent from '../components/max_velocity'; +import PointsColliderComponent from '../components/points_collider'; +import PointsComponent from '../components/points'; import PositionComponent from '@serpentity/components.position'; import PixiContainerComponent from '../components/pixi_container'; +import WinnerComponent from '../components/winner'; import PixiFactory from '../factories/pixi'; import Config from '../config'; @@ -68,9 +74,12 @@ export default { // RENDERING const radius = 25; + const pixiConfig = Object.assign({ + radius + }, config.pixi); const container = config.container || { - container: PixiFactory.createSumo({ radius }) + container: PixiFactory.createSumo(pixiConfig) }; container.container.position.x = position.x; container.container.position.y = position.y; @@ -80,10 +89,10 @@ export default { // PHYSICS const frictionAir = 0.02; - const friction = 1; - const frictionStatic = 1; - const restitution = 0.9; - const density = 1; + const friction = 0.01; + const frictionStatic = 0.01; + 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', @@ -96,6 +105,18 @@ export default { }); entity.addComponent(new BodyComponent({ body })); + // GRAB + + const areaSizeFactor = 2; // Multiplier vs the radius + const area = Bodies.circle(position.x / Config.meterSize, position.y / Config.meterSize, (radius * areaSizeFactor) / Config.meterSize, { + label: 'Sumo Grab Area', + isSensor: true + }); + + entity.addComponent(new GrabAreaComponent({ area })); + entity.addComponent(new GrabComponent({ body })); + entity.addComponent(new GrabbableComponent({ body })); + if (engine) { engine.addEntity(entity); } @@ -180,64 +201,304 @@ export default { const entity = this.createSumo(null, config); - entity.addComponent(new ControlMapComponent({ - map: [ - { - source: { - type: 'keyboard', - index: 37 // left arrow + entity.addComponent(new ControlMapComponent(config.controlMap)); + + 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. Has contrrol scheme defaults for + * player 1 + * + * @function createPlayer1Sumo + * @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 + */ + createPlayer1Sumo(engine, config = {}) { + + const playerConfig = Object.assign({ + controlMap: { + map: [ + { + source: { + type: 'keyboard', + index: 65 // a + }, + target: { + component: ForceComponent, + property: 'x', + value: (value) => -Number(value) + } }, - target: { - component: ForceComponent, - property: 'x', - value: (value) => -Number(value) - } - }, - { - source: { - type: 'keyboard', - index: 39 // right arrow + { + source: { + type: 'keyboard', + index: 68 // d + }, + target: { + component: ForceComponent, + property: 'x', + value: (value) => Number(value) + } }, - target: { - component: ForceComponent, - property: 'x', - value: (value) => Number(value) - } - }, - { - source: { - type: 'keyboard', - index: 38 // up arrow + { + source: { + type: 'keyboard', + index: 87 // w + }, + target: { + component: ForceComponent, + property: 'y', + value: (value) => -Number(value) + } }, - target: { - component: ForceComponent, - property: 'y', - value: (value) => -Number(value) - } - }, - { - source: { - type: 'keyboard', - index: 40 // down arrow + { + source: { + type: 'keyboard', + index: 83 // s + }, + target: { + component: ForceComponent, + property: 'y', + value: (value) => Number(value) + } + }, + { + source: { + type: 'keyboard', + index: 90 // Z + }, + target: { + component: DashComponent, + property: 'dashing' + } + }, + { + source: { + type: 'keyboard', + index: 88 // X + }, + target: { + component: GrabComponent, + property: 'grabbing' + } + }, + { + source: { + type: 'gamepad', + gamepadNumber: 0, + gamepadInputSource: 'axes', + index: 0 // left stick horizontal + }, + target: { + component: ForceComponent, + property: 'x', + value: (value) => Number(value) + } + }, + { + source: { + type: 'gamepad', + gamepadNumber: 0, + gamepadInputSource: 'axes', + index: 1 // left stick vertical + }, + target: { + component: ForceComponent, + property: 'y', + value: (value) => Number(value) + } + }, + { + source: { + type: 'gamepad', + gamepadNumber: 0, + gamepadInputSource: 'buttons', + index: 2 // left face button + }, + target: { + component: DashComponent, + property: 'dashing', + value: (value) => value.value + } }, - target: { - component: ForceComponent, - property: 'y', - value: (value) => Number(value) + { + source: { + type: 'gamepad', + gamepadNumber: 0, + gamepadInputSource: 'buttons', + index: 0 // bottom face button + }, + target: { + component: GrabComponent, + property: 'grabbing', + value: (value) => value.value + } } - }, - { - source: { - type: 'keyboard', - index: 90 // Z + ] + } + }, config); + + const entity = this.createControllableSumo(null, playerConfig); + + 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. Has contrrol scheme defaults for + * player 2 + * + * @function createPlayer2Sumo + * @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 + */ + createPlayer2Sumo(engine, config = {}) { + + const playerConfig = Object.assign({ + pixi: { + color: 0xeaacac + }, + controlMap: { + 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) + } }, - target: { - component: DashComponent, - property: 'dashing' + { + source: { + type: 'keyboard', + index: 40 // down arrow + }, + target: { + component: ForceComponent, + property: 'y', + value: (value) => Number(value) + } + }, + { + source: { + type: 'keyboard', + index: 188 // , + }, + target: { + component: DashComponent, + property: 'dashing' + } + }, + { + source: { + type: 'keyboard', + index: 190 // . + }, + target: { + component: GrabComponent, + property: 'grabbing' + } + }, + { + source: { + type: 'gamepad', + gamepadNumber: 1, + gamepadInputSource: 'axes', + index: 0 // left stick horizontal + }, + target: { + component: ForceComponent, + property: 'x', + value: (value) => Number(value) + } + }, + { + source: { + type: 'gamepad', + gamepadNumber: 1, + gamepadInputSource: 'axes', + index: 1 // left stick vertical + }, + target: { + component: ForceComponent, + property: 'y', + value: (value) => Number(value) + } + }, + { + source: { + type: 'gamepad', + gamepadNumber: 1, + gamepadInputSource: 'buttons', + index: 2 // left face button + }, + target: { + component: DashComponent, + property: 'dashing', + value: (value) => value.value + } + }, + { + source: { + type: 'gamepad', + gamepadNumber: 1, + gamepadInputSource: 'buttons', + index: 0 // bottom face button + }, + target: { + component: GrabComponent, + property: 'grabbing', + value: (value) => value.value + } } - } - ] - })); + ] + } + }, config); + + const entity = this.createControllableSumo(null, playerConfig); if (engine) { engine.addEntity(entity); @@ -296,6 +557,148 @@ 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; + }, + + /** + * Creates an invisible block + * + * @function createInvisibleBlock + * @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 + */ + createInvisibleBlock(engine, config = {}) { + + const entity = new Entity(); + + // POSITION + + entity.addComponent(new PositionComponent(config.position)); + const position = entity.getComponent(PositionComponent); + + // PHYSICS + + const friction = 0; + const frictionStatic = 0; + const restitution = 1; + const label = config.label || 'Invisible Block'; + const isSensor = !!(config.isSensor); + + const body = Bodies.rectangle(position.x / Config.meterSize, + position.y / Config.meterSize, + config.width / Config.meterSize, + config.height / Config.meterSize, + { + isSensor, + isStatic: true, + label, + friction, + restitution, + frictionStatic + }); + entity.addComponent(new BodyComponent({ body })); + + if (engine) { + engine.addEntity(entity); + } + + return entity; + }, + + /** + * Creates an invisible block that accumulates points if certain + * entity collids with it + * + * @function createPointsCollider + * @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 + */ + createPointsCollider(engine, config = {}) { + + const entity = this.createInvisibleBlock(null, Object.assign({ + isSensor: true, + label: 'Points Detector' + }, config)); + + // Points Collider + + entity.addComponent(new PointsColliderComponent(config)); + + if (engine) { + engine.addEntity(entity); + } + + return entity; + }, + + /** + * Creates an entity representing the game state + * + * @function createGameState + * @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 + */ + createGameState(engine, config = {}) { + + const entity = new Entity(); + + entity.addComponent(new PointsComponent(config)); + entity.addComponent(new WinnerComponent(config)); + + if (engine) { + engine.addEntity(entity); + } + return entity; } };