From 685f1298acea30dd5e0991b6e739061446bc06c2 Mon Sep 17 00:00:00 2001 From: -=yb4f310 Date: Sat, 24 Jun 2017 02:42:28 +0200 Subject: [PATCH] physics start (again) --- bak/game-lib-d3-shape.js | 32 +---- bak/game-lib-d3-solver.js | 86 ------------ src/game-lib-a-component-a.js | 23 +++- src/game-lib-d3-api-rigid-body.js | 173 ++++++++++++++++++++++++ src/game-lib-d3-api-shape.js | 45 +++++++ src/game-lib-d3-api-solver.js | 69 ++++++++++ src/game-lib-d3-broadphase.js | 41 ++++-- src/game-lib-d3-rigid-body.js | 192 +++++++++++++++++++++++++++ src/game-lib-d3-shape-0.js | 112 ++++++++++++++++ src/game-lib-d3-shape-box.js | 58 ++++++++ src/game-lib-d3-shape-convex-hull.js | 65 +++++++++ src/game-lib-d3-shape-cylinder.js | 75 +++++++++++ src/game-lib-d3-shape-height-map.js | 82 ++++++++++++ src/game-lib-d3-shape-plane.js | 34 +++++ src/game-lib-d3-shape-sphere.js | 51 +++++++ src/game-lib-d3-shape-tri-mesh.js | 63 +++++++++ src/game-lib-d3-solver.js | 126 ++++++++++++++++++ src/game-lib-d3-world.js | 2 +- src/game-lib-gui.js | 16 ++- src/game-lib-vector3.js | 46 ++++--- 20 files changed, 1242 insertions(+), 149 deletions(-) delete mode 100644 bak/game-lib-d3-solver.js create mode 100644 src/game-lib-d3-api-rigid-body.js create mode 100644 src/game-lib-d3-api-shape.js create mode 100644 src/game-lib-d3-api-solver.js create mode 100644 src/game-lib-d3-rigid-body.js create mode 100644 src/game-lib-d3-shape-0.js create mode 100644 src/game-lib-d3-shape-box.js create mode 100644 src/game-lib-d3-shape-convex-hull.js create mode 100644 src/game-lib-d3-shape-cylinder.js create mode 100644 src/game-lib-d3-shape-height-map.js create mode 100644 src/game-lib-d3-shape-plane.js create mode 100644 src/game-lib-d3-shape-sphere.js create mode 100644 src/game-lib-d3-shape-tri-mesh.js create mode 100644 src/game-lib-d3-solver.js diff --git a/bak/game-lib-d3-shape.js b/bak/game-lib-d3-shape.js index 4c1b234..439b65b 100644 --- a/bak/game-lib-d3-shape.js +++ b/bak/game-lib-d3-shape.js @@ -109,36 +109,14 @@ GameLib.D3.Shape.prototype.createInstance = function() { var instance = null; if (this.shapeType == GameLib.D3.Shape.SHAPE_TYPE_TRIMESH) { - instance = new this.engine.instance.Trimesh( - this.vertices, - this.indices - ); - } else if (this.shapeType == GameLib.D3.Shape.SHAPE_TYPE_SPHERE) { - instance = new this.engine.instance.Sphere( - this.radius - ); + + } else if (this.shapeType == GameLib.D3.Shape.SHAPE_TYPE_SPHERE) {; } else if (this.shapeType == GameLib.D3.Shape.SHAPE_TYPE_BOX) { - instance = new this.engine.instance.Box( - new this.engine.instance.Vec3( - this.halfExtensions.x, - this.halfExtensions.y, - this.halfExtensions.z - ) - ); + } else if (this.shapeType == GameLib.D3.Shape.SHAPE_TYPE_CYLINDER) { - instance = new this.engine.instance.Cylinder( - this.radiusTop, - this.radiusBottom, - this.height, - this.numSegments - ); + } else if (this.shapeType == GameLib.D3.Shape.SHAPE_TYPE_HEIGHT_MAP) { - instance = new this.engine.instance.Heightfield( - this.heightmap.matrix, - { - elementSize: this.heightmap.elementSize - } - ); + } else if (this.shapeType == GameLib.D3.Shape.SHAPE_TYPE_CONVEX_HULL) { instance = new this.engine.instance.ConvexPolyhedron( diff --git a/bak/game-lib-d3-solver.js b/bak/game-lib-d3-solver.js deleted file mode 100644 index 00e489d..0000000 --- a/bak/game-lib-d3-solver.js +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Physics Solver Superset - * @param id - * @param engine GameLib.D3.Engine - * @param solverType - * @param name - * @param iterations - * @param tolerance - * @constructor - */ -GameLib.D3.Solver = function( - id, - engine, - solverType, - name, - iterations, - tolerance -) { - this.id = id; - - this.engine = engine; - this.engine.isNotCannonThrow(); - - if (typeof solverType == 'undefined') { - solverType = GameLib.D3.Solver.GS_SOLVER; - } - this.solverType = solverType; - - if (typeof name == 'undefined') { - if (this.solverType == GameLib.D3.Solver.SPLIT_SOLVER) { - name = 'split solver'; - } else if (this.solverType == GameLib.D3.Solver.GS_SOLVER) { - name = 'gs solver'; - } else { - name = 'unknown solver'; - } - } - this.name = name; - - if (typeof iterations == 'undefined') { - iterations = 10; - } - this.iterations = iterations; - - if (typeof tolerance == 'undefined') { - tolerance = 1e-7; - } - this.tolerance = tolerance; - - this.instance = this.createInstance(); - - this.instance.tolerance = tolerance; - this.instance.iterations = iterations; -}; - -/** - * Creates a custom solver instance - * @returns {*} - */ -GameLib.D3.Solver.prototype.createInstance = function(){ - - var instance = null; - - if (this.solverType == GameLib.D3.Solver.SPLIT_SOLVER) { - instance = new this.engine.instance.SplitSolver(); - } else if (this.solverType == GameLib.D3.Solver.GS_SOLVER) { - instance = new this.engine.instance.GSSolver(); - } else { - console.warn('Unsupported solver type: ' + this.solverType); - throw new Error('Unsupported solver type: ' + this.solverType); - } - - return instance; -}; - -GameLib.D3.Solver.prototype.toApiSolver = function() { - return null; -}; - - -/** - * Solver Types - * @type {number} - */ -GameLib.D3.Solver.SPLIT_SOLVER = 0x1; -GameLib.D3.Solver.GS_SOLVER = 0x2; diff --git a/src/game-lib-a-component-a.js b/src/game-lib-a-component-a.js index c103045..6991e3f 100644 --- a/src/game-lib-a-component-a.js +++ b/src/game-lib-a-component-a.js @@ -121,8 +121,16 @@ GameLib.Component.COMPONENT_MESH_PLANE = 0x22; GameLib.Component.COMPONENT_MESH_CURVE = 0x23; GameLib.Component.COMPONENT_WORLD = 0x24; GameLib.Component.COMPONENT_BROADPHASE = 0x25; -GameLib.Component.COMPONENT_SOLVER = 0x25; -GameLib.Component.COMPONENT_RIGID_BODY = 0x26; +GameLib.Component.COMPONENT_SOLVER = 0x26; +GameLib.Component.COMPONENT_RIGID_BODY = 0x27; +GameLib.Component.COMPONENT_SHAPE = 0x28; +GameLib.Component.COMPONENT_SHAPE_BOX = 0x29; +GameLib.Component.COMPONENT_SHAPE_SPHERE = 0x2a; +GameLib.Component.COMPONENT_SHAPE_TRI_MESH = 0x2b; +GameLib.Component.COMPONENT_SHAPE_CONVEX_HULL = 0x2c; +GameLib.Component.COMPONENT_SHAPE_CYLINDER = 0x2d; +GameLib.Component.COMPONENT_SHAPE_HEIGHT_MAP = 0x2e; +GameLib.Component.COMPONENT_SHAPE_PLANE = 0x2f; /** * Returns string name for component number @@ -169,7 +177,16 @@ GameLib.Component.GetComponentName = function(number) { case 0x23 : return 'GameLib.D3.Mesh.Curve'; case 0x24 : return 'GameLib.D3.World'; case 0x25 : return 'GameLib.D3.Broadphase'; - case 0x26 : return 'GameLib.D3.RigidBody'; + case 0x26 : return 'GameLib.D3.Solver'; + case 0x27 : return 'GameLib.D3.RigidBody'; + case 0x28 : return 'GameLib.D3.Shape'; + case 0x29 : return 'GameLib.D3.Shape.Box'; + case 0x2a : return 'GameLib.D3.Shape.Sphere'; + case 0x2b : return 'GameLib.D3.Shape.TriMesh'; + case 0x2c : return 'GameLib.D3.Shape.ConvexHull'; + case 0x2d : return 'GameLib.D3.Shape.Cylinder'; + case 0x2e : return 'GameLib.D3.Shape.HeightMap'; + case 0x2f : return 'GameLib.D3.Shape.Plane'; break; } }; diff --git a/src/game-lib-d3-api-rigid-body.js b/src/game-lib-d3-api-rigid-body.js new file mode 100644 index 0000000..6a9306a --- /dev/null +++ b/src/game-lib-d3-api-rigid-body.js @@ -0,0 +1,173 @@ +/** + * Raw RigidBody API object - should always correspond with the RigidBody Schema + * @param id + * @param name + * @param mass + * @param friction + * @param position + * @param quaternion + * @param velocity + * @param angularVelocity + * @param linearDamping + * @param angularDamping + * @param allowSleep + * @param sleepSpeedLimit + * @param sleepTimeLimit + * @param collisionFilterGroup + * @param collisionFilterMask + * @param fixedRotation + * @param shape + * @param kinematic + * @param parentEntity + * @constructor + */ +GameLib.D3.API.RigidBody = function( + id, + name, + mass, + friction, + position, + quaternion, + velocity, + angularVelocity, + linearDamping, + angularDamping, + allowSleep, + sleepSpeedLimit, + sleepTimeLimit, + collisionFilterGroup, + collisionFilterMask, + fixedRotation, + shape, + kinematic, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'RigidBody (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(mass)) { + mass = 0; + } + this.mass = mass; + + if (GameLib.Utils.UndefinedOrNull(friction)) { + friction = 5; + } + this.friction = friction; + + if (GameLib.Utils.UndefinedOrNull(position)) { + position = new GameLib.API.Vector3(0,0,0); + } + this.position = position; + + if (GameLib.Utils.UndefinedOrNull(quaternion)) { + quaternion = new GameLib.API.Quaternion(); + } + this.quaternion = quaternion; + + if (GameLib.Utils.UndefinedOrNull(velocity)) { + velocity = new GameLib.API.Vector3(); + } + this.velocity = velocity; + + if (GameLib.Utils.UndefinedOrNull(angularVelocity)) { + angularVelocity = new GameLib.API.Vector3(); + } + this.angularVelocity = angularVelocity; + + if (GameLib.Utils.UndefinedOrNull(linearDamping)) { + linearDamping = 0.01; + } + this.linearDamping = linearDamping; + + if (GameLib.Utils.UndefinedOrNull(angularDamping)) { + angularDamping = 0.01; + } + this.angularDamping = angularDamping; + + if (GameLib.Utils.UndefinedOrNull(allowSleep)) { + allowSleep = true; + } + this.allowSleep = allowSleep; + + if (GameLib.Utils.UndefinedOrNull(sleepSpeedLimit)) { + sleepSpeedLimit = 0.1; + } + this.sleepSpeedLimit = sleepSpeedLimit; + + if (GameLib.Utils.UndefinedOrNull(sleepTimeLimit)) { + sleepTimeLimit = 1.0; + } + this.sleepTimeLimit = sleepTimeLimit; + + if (GameLib.Utils.UndefinedOrNull(collisionFilterGroup)) { + collisionFilterGroup = 1; + } + this.collisionFilterGroup = collisionFilterGroup; + + if (GameLib.Utils.UndefinedOrNull(collisionFilterMask)) { + collisionFilterMask = 1; + } + this.collisionFilterMask = collisionFilterMask; + + if (GameLib.Utils.UndefinedOrNull(fixedRotation)) { + fixedRotation = false; + } + this.fixedRotation = fixedRotation; + + if (GameLib.Utils.UndefinedOrNull(shape)) { + shape = null; + } + this.shape = shape; + + if (GameLib.Utils.UndefinedOrNull(kinematic)) { + kinematic = false; + } + this.kinematic = kinematic; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.RigidBody.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.RigidBody.prototype.constructor = GameLib.D3.API.RigidBody; + +/** + * Creates an API RigidBody from an Object RigidBody + * @param objectRigidBody + * @constructor + */ +GameLib.D3.API.RigidBody.FromObject = function(objectRigidBody) { + return new GameLib.D3.API.RigidBody( + objectRigidBody.id, + objectRigidBody.name, + objectRigidBody.mass, + objectRigidBody.friction, + objectRigidBody.position, + objectRigidBody.quaternion, + objectRigidBody.velocity, + objectRigidBody.angularVelocity, + objectRigidBody.linearDamping, + objectRigidBody.angularDamping, + objectRigidBody.allowSleep, + objectRigidBody.sleepSpeedLimit, + objectRigidBody.sleepTimeLimit, + objectRigidBody.collisionFilterGroup, + objectRigidBody.collisionFilterMask, + objectRigidBody.fixedRotation, + objectRigidBody.shape, + objectRigidBody.kinematic, + objectRigidBody.parentEntity + ); +}; + diff --git a/src/game-lib-d3-api-shape.js b/src/game-lib-d3-api-shape.js new file mode 100644 index 0000000..7cbe4ed --- /dev/null +++ b/src/game-lib-d3-api-shape.js @@ -0,0 +1,45 @@ +/** + * Raw Shape API object - should always correspond with the Shape Schema + * @param id + * @param name + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Shape = function( + id, + name, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Shape (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Shape.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Shape.prototype.constructor = GameLib.D3.API.Shape; + +/** + * Creates an API Shape from an Object Shape + * @param objectShape + * @constructor + */ +GameLib.D3.API.Shape.FromObject = function(objectShape) { + return new GameLib.D3.API.Shape( + objectShape.id, + objectShape.name, + objectShape.parentEntity + ); +}; + diff --git a/src/game-lib-d3-api-solver.js b/src/game-lib-d3-api-solver.js new file mode 100644 index 0000000..0c2ecbd --- /dev/null +++ b/src/game-lib-d3-api-solver.js @@ -0,0 +1,69 @@ +/** + * Raw Solver API object - should always correspond with the Solver Schema + * @param id + * @param name + * @param solverType + * @param iterations + * @param tolerance + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Solver = function( + id, + name, + solverType, + iterations, + tolerance, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Solver (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(solverType)) { + solverType = GameLib.D3.Solver.GS_SOLVER; + } + this.solverType = solverType; + + if (GameLib.Utils.UndefinedOrNull(iterations)) { + iterations = 10; + } + this.iterations = iterations; + + if (GameLib.Utils.UndefinedOrNull(tolerance)) { + tolerance = 1e-7; + } + this.tolerance = tolerance; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Solver.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Solver.prototype.constructor = GameLib.D3.API.Solver; + +/** + * Creates an API Solver from an Object Solver + * @param objectSolver + * @constructor + */ +GameLib.D3.API.Solver.FromObject = function(objectSolver) { + return new GameLib.D3.API.Solver( + objectSolver.id, + objectSolver.name, + objectSolver.solverType, + objectSolver.iterations, + objectSolver.tolerance, + objectSolver.parentEntity + ); +}; + diff --git a/src/game-lib-d3-broadphase.js b/src/game-lib-d3-broadphase.js index 7b66ff0..2281973 100644 --- a/src/game-lib-d3-broadphase.js +++ b/src/game-lib-d3-broadphase.js @@ -30,9 +30,7 @@ GameLib.D3.Broadphase = function ( GameLib.Component.call( this, - GameLib.Component.COMPONENT_BROADPHASE, - { - } + GameLib.Component.COMPONENT_BROADPHASE ); }; @@ -45,16 +43,14 @@ GameLib.D3.Broadphase.prototype.constructor = GameLib.D3.Broadphase; */ GameLib.D3.Broadphase.prototype.createInstance = function() { - - //todo var instance = null; - if (this.broadphaseType == GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE) { - instance = new this.engine.instance.NaiveBroadphase(); - } else if (this.broadphaseType == GameLib.D3.Broadphase.BROADPHASE_TYPE_GRID) { - instance = new this.engine.instance.GridBroadphase(); - } else if (this.broadphaseType == GameLib.D3.Broadphase.BROADPHASE_TYPE_SAP) { - instance = new this.engine.instance.SAPBroadphase(); + if (this.broadphaseType === GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE) { + instance = new CANNON.NaiveBroadphase(); + } else if (this.broadphaseType === GameLib.D3.Broadphase.BROADPHASE_TYPE_GRID) { + instance = new CANNON.GridBroadphase(); + } else if (this.broadphaseType === GameLib.D3.Broadphase.BROADPHASE_TYPE_SAP) { + instance = new CANNON.SAPBroadphase(); } else { console.warn('Unsupported broadphase type: ' + this.broadphaseType); throw new Error('Unsupported broadphase type: ' + this.broadphaseType); @@ -67,7 +63,24 @@ GameLib.D3.Broadphase.prototype.createInstance = function() { * */ GameLib.D3.Broadphase.prototype.updateInstance = function() { - //todo + + if (this.broadphaseType === GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE) { + if (!(this.instance instanceof CANNON.NaiveBroadphase)) { + this.instance = new CANNON.NaiveBroadphase(); + } + } + + if (this.broadphaseType === GameLib.D3.Broadphase.BROADPHASE_TYPE_GRID) { + if (!(this.instance instanceof CANNON.GridBroadphase)) { + this.instance = new CANNON.GridBroadphase(); + } + } + + if (this.broadphaseType === GameLib.D3.Broadphase.BROADPHASE_TYPE_SAP) { + if (!(this.instance instanceof CANNON.SAPBroadphase)) { + this.instance = new CANNON.SAPBroadphase(); + } + } }; /** @@ -108,5 +121,5 @@ GameLib.D3.Broadphase.FromObject = function(graphics, objectComponent) { * @type {number} */ GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE = 0x1; -GameLib.D3.Broadphase.BROADPHASE_TYPE_GRID = 0x2; -GameLib.D3.Broadphase.BROADPHASE_TYPE_SAP = 0x3; \ No newline at end of file +GameLib.D3.Broadphase.BROADPHASE_TYPE_GRID = 0x2; +GameLib.D3.Broadphase.BROADPHASE_TYPE_SAP = 0x3; \ No newline at end of file diff --git a/src/game-lib-d3-rigid-body.js b/src/game-lib-d3-rigid-body.js new file mode 100644 index 0000000..2825a00 --- /dev/null +++ b/src/game-lib-d3-rigid-body.js @@ -0,0 +1,192 @@ +/** + * RigidBody Runtime + * @param physics GameLib.D3.Graphics + * @param apiRigidBody GameLib.D3.API.RigidBody + * @constructor + */ +GameLib.D3.RigidBody = function ( + physics, + apiRigidBody +) { + + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiRigidBody)) { + apiRigidBody = {}; + } + + if (apiRigidBody instanceof GameLib.D3.RigidBody) { + return apiRigidBody; + } + + GameLib.D3.API.RigidBody.call( + this, + apiRigidBody.id, + apiRigidBody.name, + apiRigidBody.mass, + apiRigidBody.friction, + apiRigidBody.position, + apiRigidBody.quaternion, + apiRigidBody.velocity, + apiRigidBody.angularVelocity, + apiRigidBody.linearDamping, + apiRigidBody.angularDamping, + apiRigidBody.allowSleep, + apiRigidBody.sleepSpeedLimit, + apiRigidBody.sleepTimeLimit, + apiRigidBody.collisionFilterGroup, + apiRigidBody.collisionFilterMask, + apiRigidBody.fixedRotation, + apiRigidBody.shape, + apiRigidBody.kinematic, + apiRigidBody.parentEntity + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_RIGID_BODY, + { + 'shape' : GameLib.D3.Shape + } + ); +}; + +GameLib.D3.RigidBody.prototype = Object.create(GameLib.D3.API.RigidBody.prototype); +GameLib.D3.RigidBody.prototype.constructor = GameLib.D3.RigidBody; + +/** + * + * @returns {*} + */ +GameLib.D3.RigidBody.prototype.createInstance = function() { + + //TODO: create instance + + var instance = new CANNON.Body( + { + mass : this.mass, + friction : this.friction, + position : new CANNON.Vec3( + this.position.x, + this.position.y, + this.position.z + ), + quaternion : new CANNON.Quaternion( + this.quaternion.x, + this.quaternion.y, + this.quaternion.z, + this.quaternion.w + ), + velocity : new CANNON.Vec3( + this.velocity.x, + this.velocity.y, + this.velocity.z + ), + angularVelocity : this.angularVelocity, + linearDamping : this.linearDamping, + angularDamping : this.angularDamping, + allowSleep : this.allowSleep, + sleepSpeedLimit : this.sleepSpeedLimit, + sleepTimeLimit : this.sleepTimeLimit, + collisionFilterGroup : this.collisionFilterGroup, + collisionFilterMask : this.collisionFilterMask, + fixedRotation : this.fixedRotation, + kinematic : this.kinematic + } + ); + + this.shapes.map(function(shape){ + + if (shape.loaded) { + instance.addShape(shape.instance) + } else { + console.warn('todo : listen for shape created and add here'); + throw new Error('todo : listen for shape created and add here'); + } + + }); + + return instance; +}; + +/** + * + */ +GameLib.D3.RigidBody.prototype.updateInstance = function() { + + this.instance.mass = this.mass; + this.instance.friction = this.friction; + + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + + this.instance.quaternion.x = this.quaternion.x; + this.instance.quaternion.y = this.quaternion.y; + this.instance.quaternion.z = this.quaternion.z; + this.instance.quaternion.w = this.quaternion.w; + + this.instance.velocity.x = this.velocity.x; + this.instance.velocity.y = this.velocity.y; + this.instance.velocity.z = this.velocity.z; + + this.instance.angularVelocity = this.angularVelocity; + this.instance.linearDamping = this.linearDamping; + this.instance.angularDamping = this.angularDamping; + this.instance.allowSleep = this.allowSleep; + this.instance.sleepSpeedLimit = this.sleepSpeedLimit; + this.instance.sleepTimeLimit = this.sleepTimeLimit; + this.instance.collisionFilterGroup = this.collisionFilterGroup; + this.instance.collisionFilterMask = this.collisionFilterMask; + this.instance.fixedRotation = this.fixedRotation; + this.instance.kinematic = this.kinematic; +}; + +/** + * GameLib.D3.RigidBody to GameLib.D3.API.RigidBody + * @returns {GameLib.D3.API.RigidBody} + */ +GameLib.D3.RigidBody.prototype.toApiObject = function() { + + var apiRigidBody = new GameLib.D3.API.RigidBody( + this.id, + this.name, + this.mass, + this.friction, + this.position, + this.quaternion, + this.velocity, + this.angularVelocity, + this.linearDamping, + this.angularDamping, + this.allowSleep, + this.sleepSpeedLimit, + this.sleepTimeLimit, + this.collisionFilterGroup, + this.collisionFilterMask, + this.fixedRotation, + GameLib.Utils.IdOrNull(this.shape), + this.kinematic, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiRigidBody; +}; + +/** + * GameLib.D3.RigidBody from Object RigidBody + * @param graphics + * @param objectComponent + * @returns {GameLib.D3.RigidBody} + * @constructor + */ +GameLib.D3.RigidBody.FromObject = function(graphics, objectComponent) { + + var apiRigidBody = GameLib.D3.API.RigidBody.FromObject(objectComponent); + + return new GameLib.D3.RigidBody( + graphics, + apiRigidBody + ); +}; diff --git a/src/game-lib-d3-shape-0.js b/src/game-lib-d3-shape-0.js new file mode 100644 index 0000000..f750c3f --- /dev/null +++ b/src/game-lib-d3-shape-0.js @@ -0,0 +1,112 @@ +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics GameLib.D3.Physics + * @param apiShape GameLib.D3.API.Shape + * @constructor + */ +GameLib.D3.Shape = function ( + physics, + apiShape +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiShape)) { + apiShape = {}; + } + + if (apiShape instanceof GameLib.D3.Shape) { + return apiShape; + } + + GameLib.D3.API.Shape.call( + this, + apiShape.id, + apiShape.name, + apiShape.parentEntity + ); + + var componentType = GameLib.Component.COMPONENT_SHAPE; + + if (this instanceof GameLib.D3.Shape.Box) { + componentType = GameLib.Component.COMPONENT_SHAPE_BOX; + } + + if (this instanceof GameLib.D3.Shape.Sphere) { + componentType = GameLib.Component.COMPONENT_SHAPE_SPHERE; + } + + if (this instanceof GameLib.D3.Shape.TriMesh) { + componentType = GameLib.Component.COMPONENT_SHAPE_TRI_MESH; + } + + if (this instanceof GameLib.D3.Shape.Plane) { + componentType = GameLib.Component.COMPONENT_SHAPE_PLANE; + } + + if (this instanceof GameLib.D3.Shape.HeightMap) { + componentType = GameLib.Component.COMPONENT_SHAPE_HEIGHT_MAP; + } + + if (this instanceof GameLib.D3.Shape.Cylinder) { + componentType = GameLib.Component.COMPONENT_SHAPE_CYLINDER; + } + + if (this instanceof GameLib.D3.Shape.ConvexHull) { + componentType = GameLib.Component.SHAPE_TYPE_CONVEX_HULL; + } + + GameLib.Component.call( + this, + componentType + ); +}; + +GameLib.D3.Shape.prototype = Object.create(GameLib.D3.API.Shape.prototype); +GameLib.D3.Shape.prototype.constructor = GameLib.D3.Shape; + +/** + * Creates a shape instance or updates it + */ +GameLib.D3.Shape.prototype.createInstance = function() { + throw new Error('Do not instantiate this class directly - use a child class instead'); +}; + +/** + * Updates the mesh instance + */ +GameLib.D3.Shape.prototype.updateInstance = function() { + throw new Error('Do not instantiate this class directly - use a child class instead'); +}; + +/** + * Converts a GameLib.D3.Shape to a GameLib.D3.API.Shape + * @returns {GameLib.D3.API.Shape} + */ +GameLib.D3.Shape.prototype.toApiObject = function() { + + var apiShape = new GameLib.D3.API.Shape( + this.id, + this.name, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiShape; +}; + +/** + * Converts a standard object mesh to a GameLib.D3.Shape + * @param graphics GameLib.D3.Graphics + * @param objectShape {Object} + * @constructor + */ +GameLib.D3.Shape.FromObject = function(graphics, objectShape) { + + var apiShape = GameLib.D3.API.Shape.FromObject(objectShape); + + return new GameLib.D3.Shape( + graphics, + apiShape + ); + +}; diff --git a/src/game-lib-d3-shape-box.js b/src/game-lib-d3-shape-box.js new file mode 100644 index 0000000..d8f383f --- /dev/null +++ b/src/game-lib-d3-shape-box.js @@ -0,0 +1,58 @@ +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape GameLib.D3.API.Shape + * @param halfExtents + * @constructor + */ +GameLib.D3.Shape.Box = function ( + physics, + apiShape, + halfExtents +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(halfExtents)) { + halfExtents = new GameLib.Vector3( + physics, + new GameLib.API.Vector3( + 1,1,1 + ) + ); + } + this.halfExtents = halfExtents; + + GameLib.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +GameLib.D3.Shape.Box.prototype = Object.create(GameLib.D3.Shape.prototype); +GameLib.D3.Shape.Box.prototype.constructor = GameLib.D3.Shape.Box; + +/** + * + * @returns {GameLib.D3.Shape.Box|*|SEA3D.Box} + */ +GameLib.D3.Shape.Box.prototype.createInstance = function() { + + var instance = new CANNON.Box( + this.halfExtents.instance + ); + + return instance; +}; + +GameLib.D3.Shape.Box.prototype.updateInstance = function() { + this.instance.halfExtents.x = this.halfExtents.x; + this.instance.halfExtents.y = this.halfExtents.y; + this.instance.halfExtents.z = this.halfExtents.z; + this.instance.updateAABB(); + this.instance.updateBoundingSphereRadius(); + this.instance.updateEdges(); + this.instance.updateNormals(); + this.instance.updateTree(); +}; \ No newline at end of file diff --git a/src/game-lib-d3-shape-convex-hull.js b/src/game-lib-d3-shape-convex-hull.js new file mode 100644 index 0000000..8b7ece5 --- /dev/null +++ b/src/game-lib-d3-shape-convex-hull.js @@ -0,0 +1,65 @@ +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape GameLib.D3.API.Shape + * @param points + * @param faces + * @constructor + */ +GameLib.D3.Shape.ConvexHull = function ( + physics, + apiShape, + points, + faces +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(points)) { + points = []; + } + this.points = points; + + if (GameLib.Utils.UndefinedOrNull(faces)) { + faces = []; + } + this.faces = faces; + + GameLib.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +GameLib.D3.Shape.ConvexHull.prototype = Object.create(GameLib.D3.Shape.prototype); +GameLib.D3.Shape.ConvexHull.prototype.constructor = GameLib.D3.Shape.ConvexHull; + +/** + * Create instance + * @returns {GameLib.D3.Shape.ConvexHull} + */ +GameLib.D3.Shape.ConvexHull.prototype.createInstance = function() { + + var instance = new CANNON.ConvexPolyhedron( + this.points.map(function(point){ + return point.instance; + }), + this.faces + ); + + return instance; +}; + +/** + * Update instance + */ +GameLib.D3.Shape.ConvexHull.prototype.updateInstance = function() { + // this.instance.vertices = this.vertices; + // this.instance.indices = this.indices; + // this.instance.updateAABB(); + // this.instance.updateBoundingSphereRadius(); + // this.instance.updateEdges(); + // this.instance.updateNormals(); + // this.instance.updateTree(); +}; \ No newline at end of file diff --git a/src/game-lib-d3-shape-cylinder.js b/src/game-lib-d3-shape-cylinder.js new file mode 100644 index 0000000..fd37c1b --- /dev/null +++ b/src/game-lib-d3-shape-cylinder.js @@ -0,0 +1,75 @@ +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape GameLib.D3.API.Shape + * @param radiusTop + * @param radiusBottom + * @param height + * @param numSegments + * @constructor + */ +GameLib.D3.Shape.Cylinder = function ( + physics, + apiShape, + radiusTop, + radiusBottom, + height, + numSegments +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(radiusTop)) { + radiusTop = 1; + } + this.radiusTop = radiusTop; + + if (GameLib.Utils.UndefinedOrNull(radiusBottom)) { + radiusBottom = 1; + } + this.radiusBottom = radiusBottom; + + if (GameLib.Utils.UndefinedOrNull(height)) { + height = 1; + } + this.height = height; + + if (GameLib.Utils.UndefinedOrNull(numSegments)) { + numSegments = 1; + } + this.numSegments = numSegments; + + GameLib.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +GameLib.D3.Shape.Cylinder.prototype = Object.create(GameLib.D3.Shape.prototype); +GameLib.D3.Shape.Cylinder.prototype.constructor = GameLib.D3.Shape.Cylinder; + +/** + * + * @returns {GameLib.D3.Shape.Cylinder|*|SEA3D.Cylinder} + */ +GameLib.D3.Shape.Cylinder.prototype.createInstance = function() { + + var instance = new CANNON.Cylinder( + this.radiusTop, + this.radiusBottom, + this.height, + this.numSegments + ); + + return instance; +}; + +GameLib.D3.Shape.Cylinder.prototype.updateInstance = function() { + // this.instance.radius = this.radius; + // this.instance.updateAABB(); + // this.instance.updateBoundingCylinderRadius(); + // this.instance.updateEdges(); + // this.instance.updateNormals(); + // this.instance.updateTree(); +}; \ No newline at end of file diff --git a/src/game-lib-d3-shape-height-map.js b/src/game-lib-d3-shape-height-map.js new file mode 100644 index 0000000..666a882 --- /dev/null +++ b/src/game-lib-d3-shape-height-map.js @@ -0,0 +1,82 @@ +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape GameLib.D3.API.Shape + * @param data + * @param minValue + * @param maxValue + * @param elementSize + * @constructor + */ +GameLib.D3.Shape.HeightMap = function ( + physics, + apiShape, + data, + minValue, + maxValue, + elementSize +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(data)) { + data = []; + } + this.data = data; + + if (GameLib.Utils.UndefinedOrNull(minValue)) { + minValue = undefined; + } + this.minValue = minValue; + + if (GameLib.Utils.UndefinedOrNull(maxValue)) { + maxValue = undefined; + } + this.maxValue = maxValue; + + if (GameLib.Utils.UndefinedOrNull(elementSize)) { + elementSize = 0.1; + } + this.elementSize = elementSize; + + GameLib.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +GameLib.D3.Shape.HeightMap.prototype = Object.create(GameLib.D3.Shape.prototype); +GameLib.D3.Shape.HeightMap.prototype.constructor = GameLib.D3.Shape.HeightMap; + +/** + * Create instance + * @returns {GameLib.D3.Shape.HeightMap} + */ +GameLib.D3.Shape.HeightMap.prototype.createInstance = function() { + + var instance = new CANNON.Heightfield( + this.data, + { + minValue : this.minValue, + maxValue : this.maxValue, + elemSize : this.elementSize + } + ); + + return instance; +}; + +/** + * Update instance + */ +GameLib.D3.Shape.HeightMap.prototype.updateInstance = function() { + this.instance.data = this.data; + this.instance.minValue = this.minValue; + this.instance.maxValue = this.maxValue; + this.instance.elemSize = this.elemSize; + this.instance.update(); + // this.instance.updateBoundingSphereRadius(); + // this.instance.updateMaxValue(); + // this.instance.updateMinValue(); +}; \ No newline at end of file diff --git a/src/game-lib-d3-shape-plane.js b/src/game-lib-d3-shape-plane.js new file mode 100644 index 0000000..75762ab --- /dev/null +++ b/src/game-lib-d3-shape-plane.js @@ -0,0 +1,34 @@ +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape GameLib.D3.API.Shape + * @constructor + */ +GameLib.D3.Shape.Plane = function ( + physics, + apiShape +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + GameLib.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +GameLib.D3.Shape.Plane.prototype = Object.create(GameLib.D3.Shape.prototype); +GameLib.D3.Shape.Plane.prototype.constructor = GameLib.D3.Shape.Plane; + +/** + * + * @returns {GameLib.D3.Shape.Plane|*|SEA3D.Plane} + */ +GameLib.D3.Shape.Plane.prototype.createInstance = function() { + var instance = new CANNON.Plane(); + return instance; +}; + +GameLib.D3.Shape.Plane.prototype.updateInstance = function() { +}; \ No newline at end of file diff --git a/src/game-lib-d3-shape-sphere.js b/src/game-lib-d3-shape-sphere.js new file mode 100644 index 0000000..d7ec1a9 --- /dev/null +++ b/src/game-lib-d3-shape-sphere.js @@ -0,0 +1,51 @@ +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape GameLib.D3.API.Shape + * @param radius + * @constructor + */ +GameLib.D3.Shape.Sphere = function ( + physics, + apiShape, + radius +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(radius)) { + radius = 1; + } + this.radius = radius; + + GameLib.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +GameLib.D3.Shape.Sphere.prototype = Object.create(GameLib.D3.Shape.prototype); +GameLib.D3.Shape.Sphere.prototype.constructor = GameLib.D3.Shape.Sphere; + +/** + * + * @returns {GameLib.D3.Shape.Sphere|*|SEA3D.Sphere} + */ +GameLib.D3.Shape.Sphere.prototype.createInstance = function() { + + var instance = new CANNON.Sphere( + this.radius + ); + + return instance; +}; + +GameLib.D3.Shape.Sphere.prototype.updateInstance = function() { + this.instance.radius = this.radius; + this.instance.updateAABB(); + this.instance.updateBoundingSphereRadius(); + this.instance.updateEdges(); + this.instance.updateNormals(); + this.instance.updateTree(); +}; \ No newline at end of file diff --git a/src/game-lib-d3-shape-tri-mesh.js b/src/game-lib-d3-shape-tri-mesh.js new file mode 100644 index 0000000..27334f1 --- /dev/null +++ b/src/game-lib-d3-shape-tri-mesh.js @@ -0,0 +1,63 @@ +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape GameLib.D3.API.Shape + * @param vertices + * @param indices + * @constructor + */ +GameLib.D3.Shape.TriMesh = function ( + physics, + apiShape, + vertices, + indices +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(vertices)) { + vertices = []; + } + this.vertices = vertices; + + if (GameLib.Utils.UndefinedOrNull(indices)) { + indices = []; + } + this.indices = indices; + + GameLib.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +GameLib.D3.Shape.TriMesh.prototype = Object.create(GameLib.D3.Shape.prototype); +GameLib.D3.Shape.TriMesh.prototype.constructor = GameLib.D3.Shape.TriMesh; + +/** + * Create instance + * @returns {GameLib.D3.Shape.TriMesh} + */ +GameLib.D3.Shape.TriMesh.prototype.createInstance = function() { + + var instance = new CANNON.TriMesh( + this.vertices, + this.indices + ); + + return instance; +}; + +/** + * Update instance + */ +GameLib.D3.Shape.TriMesh.prototype.updateInstance = function() { + this.instance.vertices = this.vertices; + this.instance.indices = this.indices; + this.instance.updateAABB(); + this.instance.updateBoundingSphereRadius(); + this.instance.updateEdges(); + this.instance.updateNormals(); + this.instance.updateTree(); +}; \ No newline at end of file diff --git a/src/game-lib-d3-solver.js b/src/game-lib-d3-solver.js new file mode 100644 index 0000000..38c8dd0 --- /dev/null +++ b/src/game-lib-d3-solver.js @@ -0,0 +1,126 @@ +/** + * Solver Runtime + * @param physics GameLib.D3.Graphics + * @param apiSolver GameLib.D3.API.Solver + * @constructor + */ +GameLib.D3.Solver = function ( + physics, + apiSolver +) { + + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiSolver)) { + apiSolver = {}; + } + + if (apiSolver instanceof GameLib.D3.Solver) { + return apiSolver; + } + + GameLib.D3.API.Solver.call( + this, + apiSolver.id, + apiSolver.name, + apiSolver.solverType, + apiSolver.iterations, + apiSolver.tolerance, + apiSolver.parentEntity + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_SOLVER + ); +}; + +GameLib.D3.Solver.prototype = Object.create(GameLib.D3.API.Solver.prototype); +GameLib.D3.Solver.prototype.constructor = GameLib.D3.Solver; + +/** + * + * @returns {*} + */ +GameLib.D3.Solver.prototype.createInstance = function() { + + var instance = null; + + if (this.solverType === GameLib.D3.Solver.GS_SOLVER) { + instance = new CANNON.GSSolver(); + } else if (this.solverType === GameLib.D3.Solver.SPLIT_SOLVER) { + instance = new CANNON.SplitSolver(); + } else { + console.warn('Unsupported solver type: ' + this.solverType); + throw new Error('Unsupported solver type: ' + this.solverType); + } + + instance.tolerance = this.tolerance; + instance.iterations = this.iterations; + + return instance; +}; + +/** + * + */ +GameLib.D3.Solver.prototype.updateInstance = function() { + + if (this.solverType === GameLib.D3.Solver.GS_SOLVER) { + if (!(this.instance instanceof CANNON.GSSolver)) { + this.instance = new CANNON.GSSolver(); + } + } + + if (this.solverType === GameLib.D3.Solver.SPLIT_SOLVER) { + if (!(this.instance instanceof CANNON.SplitSolver)) { + this.instance = new CANNON.SplitSolver(); + } + } + + this.instance.iterations = this.iterations; + this.instance.tolerance = this.tolerance; +}; + +/** + * GameLib.D3.Solver to GameLib.D3.API.Solver + * @returns {GameLib.D3.API.Solver} + */ +GameLib.D3.Solver.prototype.toApiObject = function() { + + var apiSolver = new GameLib.D3.API.Solver( + this.id, + this.name, + this.solverType, + this.iterations, + this.tolerance, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiSolver; +}; + +/** + * GameLib.D3.Solver from Object Solver + * @param graphics + * @param objectComponent + * @returns {GameLib.D3.Solver} + * @constructor + */ +GameLib.D3.Solver.FromObject = function(graphics, objectComponent) { + + var apiSolver = GameLib.D3.API.Solver.FromObject(objectComponent); + + return new GameLib.D3.Solver( + graphics, + apiSolver + ); +}; + +/** + * Solver Types + * @type {number} + */ +GameLib.D3.Solver.GS_SOLVER = 0x1; +GameLib.D3.Solver.SPLIT_SOLVER = 0x2; diff --git a/src/game-lib-d3-world.js b/src/game-lib-d3-world.js index a37c900..15a2012 100644 --- a/src/game-lib-d3-world.js +++ b/src/game-lib-d3-world.js @@ -41,7 +41,7 @@ GameLib.D3.World = function( if (this.solver instanceof GameLib.D3.API.Solver) { return new GameLib.D3.Solver( this.physics, - this.broadphase + this.solver ); } diff --git a/src/game-lib-gui.js b/src/game-lib-gui.js index 1feb735..0bb92ed 100644 --- a/src/game-lib-gui.js +++ b/src/game-lib-gui.js @@ -30,7 +30,7 @@ GameLib.GUI = function( var folder = this.__folders[property]; - if (folder.__listening.length == 0) { + if (folder.__listening.length === 0) { folder.close(); this.__ul.removeChild(folder.domElement.parentNode); delete this.__folders[property]; @@ -284,7 +284,19 @@ GameLib.GUI.prototype.buildControl = function(folder, object, property, entityMa } ).name(property).listen() ); - } else if (object instanceof GameLib.D3.Image && property === 'imageType') { + } else if (object instanceof GameLib.D3.Broadphase && property === 'broadphaseType') { + handles.push( + folder.add( + object, + property, + { + 'naive' : GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE, + 'grid' : GameLib.D3.Image.BROADPHASE_TYPE_GRID, + 'sap' : GameLib.D3.Image.BROADPHASE_TYPE_SAP + } + ).name(property).listen() + ); + } else if (object instanceof GameLib.D3.Image && property === 'imageType') { handles.push( folder.add( object, diff --git a/src/game-lib-vector3.js b/src/game-lib-vector3.js index 1fd19da..085ee20 100644 --- a/src/game-lib-vector3.js +++ b/src/game-lib-vector3.js @@ -1,19 +1,31 @@ /** * Runtime apiVector3 for updating instance objects - * @param graphics GameLib.D3.Graphics + * @param implementation GameLib.D3.Graphics * @param apiVector3 GameLib.API.Vector3 * @param parentObject GameLib.* * @param grain Number * @constructor */ GameLib.Vector3 = function ( - graphics, + implementation, apiVector3, parentObject, grain ) { - this.graphics = graphics; - this.graphics.isNotThreeThrow(); + + this.implementation = implementation; + + if (implementation instanceof GameLib.D3.Graphics) { + this.physics = null; + this.graphics = implementation; + this.graphics.isNotThreeThrow(); + } else if (implementation instanceof GameLib.D3.Physics) { + this.graphics = null; + this.physics = implementation; + this.physics.isNotCannonThrow(); + } else { + throw new Error('Unhandled implementation : ' + implementation); + } if (GameLib.Utils.UndefinedOrNull(apiVector3)) { apiVector3 = {}; @@ -48,24 +60,24 @@ GameLib.Vector3.prototype.constructor = GameLib.Vector3; /** * Creates an instance vector3 - * @param update * @returns {*} */ -GameLib.Vector3.prototype.createInstance = function(update) { +GameLib.Vector3.prototype.createInstance = function() { var instance = null; - if (update) { - instance = this.instance; - instance.x = this.x; - instance.y = this.y; - instance.z = this.z; - } else { - instance = new THREE.Vector3( + if (this.graphics) { + instance = new THREE.Vector3( + this.x, + this.y, + this.z + ); + } else if (this.physics) { + instance = new CANNON.Vec3( this.x, this.y, this.z - ); + ) } return instance; @@ -76,7 +88,9 @@ GameLib.Vector3.prototype.createInstance = function(update) { */ GameLib.Vector3.prototype.updateInstance = function() { - this.createInstance(true); + this.instance.x = this.x; + this.instance.y = this.y; + this.instance.z = this.z; if (this.parentObject && this.parentObject.updateInstance) { @@ -100,7 +114,7 @@ GameLib.Vector3.prototype.toApiObject = function() { */ GameLib.Vector3.prototype.copy = function() { return new GameLib.Vector3( - this.graphics, + this.implementation, new GameLib.API.Vector3( this.x, this.y,