const Static = require("./objects"); const PhSim = require("."); const Vertices = require("./tools/vertex"); const PhSimEventTarget = require("./events/eventListener"); const EventStack = require("./events/eventStack"); // Try to import matter.js as a commonJS module var Matter; if(typeof window === "object") { Matter = window.Matter; } else { Matter = require("matter-js"); } /** * * Create Dynamic Object from static object * @constructor * @memberof PhSim * @param {PhSimObject} staticObject - Static Object * @param {Matter.Body} [matterBody] - Matter Body * * @mixes PhSim.PhSimEventTarget * @mixes StaticObject * * @property {Number} x - x position * @property {Number} y - y position * */ var DynObject = function(staticObject,matterBody) { Object.assign(this,PhSimEventTarget); Object.assign(this,PhSim.Query.deepClone(staticObject)); /** * DynObject name * @type {String} */ this.name = staticObject.name; /** * DynObject type * @type {"circle" | "polygon" | "rectangle" | "regPolygon"} * */ this.type = staticObject.type; // Apply Shape Specific Constructor if(this.type === "circle") { Static.Circle.apply(this,staticObject.x,staticObject.y,staticObject.r); } if(this.type === "regPolygon") { Static.RegPolygon.apply(this,staticObject.x,staticObject.y,staticObject.radius,staticObject.sides) } if(this.type === "rectangle") { Static.Rectangle.apply(this,staticObject.x,staticObject.y,staticObject.w,staticObject.h); } if(this.type === "polygon") { Static.Polygon.apply(this,staticObject.verts); } this.widgets = staticObject.widgets; /** * Matter Body * @type {Object} */ this.matter = matterBody || PhSim.DynObject.createMatterObject(staticObject); if(staticObject.shape === "polygon") { this.skinmesh = JSON.parse(JSON.stringify(staticObject.verts)); } /** * Inital angle of object * @type {Number} */ this.firstCycle = staticObject.cycle || 0; if(staticObject.shape === "composite") { this.flattenedParts = DynObject.flattenComposite(); } /** * Reference to static object used to create the DynObject * @type {StaticObject} */ this.static = staticObject; /** * Object ID * @type {String} * */ this.id = DynObject.nextId; DynObject.nextId++; /** * Custom properties that can be added by the user to extend the DynObject. * @type {Object} */ this.data = this.data || {} /** * Reference to parent simulation * @type {null|PhSim} */ this.phSim; /** * Boolean that makes a dynamic object not collide with anything. * @type {boolean} * @default false */ this.noCollision = staticObject.noCollision || false; /** * Object containing array functions to be called. * @type {PhSim.EventStack} */ this.eventStack = new EventStack(); /** * Reference of DynObject in matter object * @type {PhSim.DynObject} * */ this.matter.plugin.dynObject = this; if(DynObject.keepInstances) { DynObject.instances.push(this); } } /** * If set to `true`, all DynObject instances are put into the * {@link PhSim.DynObject.instances} array. By default, this is `false`. * Do not use unless you want to risk memory leaks. This is primarily for debugging * purposes. * * @memberof PhSim.DynObject * @type {Boolean} * @default false */ DynObject.keepInstances = false; /** * If set to true, the `staticObject` is cloned before Object.assign is applied to * the DynObject to clone it. */ DynObject.deepCloneStaticObject = false; /** * Array of instances if {@link PhSim.DynObject.keepInstances} is set to true * @type {PhSim.DynObject[]} */ DynObject.instances = []; /** * Set color for dynObject. * This can be done alternatively by setting `dynObject.fillStyle` directly. * * @param {PhSim.DynObject} dyn_object - Dynamic Object * @param {String} colorStr - Color String */ DynObject.setColor = function(dyn_object,colorStr) { dyn_object.fillStyle = colorStr; } /** * Set color for dynObject. * This can be done alternatively by setting `dynObject.fillStyle` directly. * * @param {String} colorStr - Color String */ DynObject.prototype.setColor = function(colorStr) { return DynObject.setColor(this,colorStr) } /** * Set border color. * @param {PhSim.DynObject} dyn_object * @param {String} colorStr */ DynObject.setBorderColor = function(dyn_object,colorStr) { dyn_object.strokeStyle = colorStr; } /** * Set border color. * @param {String} colorStr */ DynObject.prototype.setBorderColor = function(colorStr) { return DynObject.setBorderColor(this,colorStr); } /** * * @param {PhSim.DynObject} dyn_object * @param {Number} lineWidth */ DynObject.setLineWidth = function(dyn_object,lineWidth) { dyn_object.lineWidth = lineWidth; } /** * * @function * @param {PhSimObject} composite - The composite to be flattened. * @returns {PhSimObject[]} - The array of objects found in the composites. */ DynObject.flattenComposite = function(composite) { var a = []; /** * * @param {*} composite * @inner */ var __f = function(composite) { for(var i = 0; i < composite.parts.length; i++) { if(composite.parts[i].shape === "composite") { DynObject.flattenComposite(composite.parts[i].shape === "composite"); } else { a.push(composite.parts[i]); } } } __f(composite); return a; } /** * * Create path * * @function * @param {Vector[]} vectorSet * @param {Path} options */ DynObject.createPath = function(vectorSet,options) { var o = new Static.Polygon(vectorSet); Object.assign(o,options); return new DynObject(o); } /** * Create circle * * @function * @param {Number} x - x-coordinate of center * @param {Number} y - y-coordinate of center * @param {Number} r - radius * @param {Circle} options - options * @returns {PhSim.DynObject} */ DynObject.createCircle = function(x,y,r,options = {}) { var o = new Static.Circle(x,y,r); Object.assign(o,options); return new DynObject(o); } /** * * Create rectangle * * @function * @param {Number} x - x-coordinate of upper left corner * @param {Number} y - y-coordinate of upper left corner * @param {Number} w - Width * @param {Number} h - Height * @param {Rectangle} options * @returns {PhSim.DynObject} - The rectangle */ DynObject.createRectangle = function(x,y,w,h,options = {}) { var o = new Static.Rectangle(x,y,w,h); Object.assign(o,options); } /** * Create regular polgyon. * * @function * @param {Number} x - x-coordinate of center * @param {Number} y - y-coordinate of center * @param {Number} r - radius * @param {Number} n - number of sides * @param {RegPolygon} options - options * @returns {PhSim.DynObject} */ DynObject.createRegPolygon = function(x,y,r,n,options = {}) { var o = new Static.RegPolygon(x,y,r,n); Object.assign(o,options); return new DynObject(o); } /** * * Create a matter.js object from a DynSim static object * * @function * @param {StaticObject} staticObject * @returns {MatterBody} */ DynObject.createMatterObject = function(staticObject) { var opts = staticObject.matter || {} opts.label = staticObject.name || "Untitled Object"; opts.isStatic = staticObject.locked || staticObject.semiLocked; var set; if(typeof staticObject.density === "number") { opts.density = staticObject.density; } else { opts.density = 0.001; } if(typeof staticObject.mass === "number") { opts.mass = staticObject.mass; opts.inverseMass = 1/staticObject.mass; } if(typeof staticObject.airFriction === "number") { opts.airFriction = staticObject.airFriction; } if(Number.isInteger(staticObject.collisionNum)) { opts.collisionFilter = staticObject.collisionNum; } if(staticObject.shape === "polygon") { return Matter.Bodies.fromVertices(Matter.Vertices.centre(staticObject.verts).x, Matter.Vertices.centre(staticObject.verts).y, staticObject.verts, opts); } else if(staticObject.shape === "circle") { return Matter.Bodies.circle(staticObject.x, staticObject.y, staticObject.radius,opts); } else if(staticObject.shape === "rectangle") { set = Vertices.rectangle(staticObject); return Matter.Bodies.fromVertices(Matter.Vertices.centre(set).x, Matter.Vertices.centre(set).y, set, opts); } else if(staticObject.shape === "regPolygon") { set = Vertices.regPolygon(staticObject); return Matter.Bodies.fromVertices(Matter.Vertices.centre(set).x, Matter.Vertices.centre(set).y, set, opts); } } DynObject.nextId = 0; /** * A PhSimObject is either a static object or a dynamic object. * * @typedef {PhSim.DynObject|StaticObject} PhSimObject * */ /** * A PhSimObject array is an array of PhSimObject objects * @typedef {PhSimObject[]} PhSimObjectArr */ module.exports = DynObject;