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;