import { Bodies, Constraint } from 'matter-js'; import { Entity } from '@serpentity/serpentity'; import AngleComponent from '../components/angle'; import BodyComponent from '../components/body'; import CoupledEntitiesComponent from '../components/coupled_entities'; import PositionComponent from '@serpentity/components.position'; import PixiContainerComponent from '../components/pixi_container'; import PixiFactory from '../factories/pixi'; const internals = { kNoEntityError: 'Entity Not Found: This method requires entityA and entityB to be set in the config.', kEntityHasNoBodyError: 'Entity Has No Body: This method requires entities have a BodyComponent.' }; /** * Factory object that contains many methods to create prefab entities. * * @type object * @name SumoFactory */ export default { /** * Creates a sumo entity and adds it to the engine. Can override * position in the config object * * @function createSumo * @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 */ createSumo(engine, config = {}) { const entity = new Entity(); // POSITION entity.addComponent(new PositionComponent(config.position)); const position = entity.getComponent(PositionComponent); entity.addComponent(new AngleComponent(config.angle)); const angle = entity.getComponent(AngleComponent); // RENDERING const radius = 25; const container = config.container || { container: PixiFactory.createSumo({ radius }) }; container.container.position.x = position.x; container.container.position.y = position.y; container.container.rotation = angle.angle; entity.addComponent(new PixiContainerComponent(container)); // PHYSICS const frictionAir = 0.00001; const friction = 0.00001; const restitution = 0.9; const density = 0.5; const body = Bodies.circle(position.x, position.y, radius, { angle: angle.angle, density, frictionAir, friction, restitution }); entity.addComponent(new BodyComponent({ body })); if (engine) { engine.addEntity(entity); } return entity; }, /** * Creates a rubber band entity and adds it to the engine. * * @function createRubberBand * @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, it * must include entityA and entityB which will be tied by it. If they * are not sent or don't have a physics body, this will throw. * @return {external:Serpentity.Entity} the created entity */ createRubberBand(engine, config = {}) { const entity = new Entity(); if (!config.entityA || !config.entityB) { throw new Error(internals.kNoEntityError); } if (!config.entityA.hasComponent(BodyComponent) || !config.entityB.hasComponent(BodyComponent)) { throw new Error(internals.kEntityHasNoBodyError); } // RENDERING const container = config.container || { container: PixiFactory.createEmptyGraphic() }; entity.addComponent(new PixiContainerComponent(container)); // PHYSICS 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 body = Constraint.create({ bodyA, bodyB, damping, length, stiffness, angularStiffness }); entity.addComponent(new BodyComponent({ body })); entity.addComponent(new CoupledEntitiesComponent({ coupledEntities: [config.entityA, config.entityB] })); if (engine) { engine.addEntity(entity); } return entity; } };