diff --git a/src/game-lib-clock.js b/src/game-lib-clock.js index ddd6c96..fc97860 100644 --- a/src/game-lib-clock.js +++ b/src/game-lib-clock.js @@ -64,7 +64,7 @@ GameLib.Clock.prototype.getDelta = function() { */ if (delta > (1 / 30.0)) { - console.log('clipped ' + (delta - (1/30.0)) + ' seconds - essentially lost time'); + // console.log('clipped ' + (delta - (1/30.0)) + ' seconds - essentially lost time'); delta = (1 / 30.0); } diff --git a/src/game-lib-d3-api-animation.js b/src/game-lib-d3-api-animation.js index da80a6b..8d14172 100644 --- a/src/game-lib-d3-api-animation.js +++ b/src/game-lib-d3-api-animation.js @@ -9,6 +9,7 @@ * @param translationFn * @param scaleFn * @param blocking + * @param applyToMeshWhenDone * @param parentMesh * @param parentEntity * @constructor @@ -23,6 +24,7 @@ GameLib.D3.API.Animation = function ( translationFn, scaleFn, blocking, + applyToMeshWhenDone, parentMesh, parentEntity ) { @@ -71,6 +73,11 @@ GameLib.D3.API.Animation = function ( } this.blocking = blocking; + if (GameLib.Utils.UndefinedOrNull(applyToMeshWhenDone)) { + applyToMeshWhenDone = true; + } + this.applyToMeshWhenDone = applyToMeshWhenDone; + if (GameLib.Utils.UndefinedOrNull(parentMesh)) { parentMesh = null; } @@ -102,6 +109,7 @@ GameLib.D3.API.Animation.FromObject = function(objectComponent) { objectComponent.translationFn, objectComponent.scaleFn, objectComponent.blocking, + objectComponent.applyToMeshWhenDone, objectComponent.parentMesh, objectComponent.parentEntity ); diff --git a/src/game-lib-d3-api-z-animation.js b/src/game-lib-d3-api-z-animation.js index 1d6b36b..5f370b4 100644 --- a/src/game-lib-d3-api-z-animation.js +++ b/src/game-lib-d3-api-z-animation.js @@ -31,6 +31,7 @@ GameLib.D3.Animation = function( apiAnimation.translationFn, apiAnimation.scaleFn, apiAnimation.blocking, + apiAnimation.applyToMeshWhenDone, apiAnimation.parentMesh, apiAnimation.parentEntity ); @@ -39,6 +40,12 @@ GameLib.D3.Animation = function( this.editor = null; + /** + * This indicates whether an animation is currently in process - for blocking to take effect + * @type {boolean} + */ + this.inProcess = false; + GameLib.Component.call( this, GameLib.Component.COMPONENT_ANIMATION @@ -159,6 +166,7 @@ GameLib.D3.Animation.prototype.toApiObject = function() { this.translationFn, this.scaleFn, this.blocking, + this.applyToMeshWhenDone, GameLib.Utils.IdOrNull(this.parentMesh), GameLib.Utils.IdOrNull(this.parentEntity) ); diff --git a/src/game-lib-d3-mesh-0.js b/src/game-lib-d3-mesh-0.js index d781bfa..324b227 100644 --- a/src/game-lib-d3-mesh-0.js +++ b/src/game-lib-d3-mesh-0.js @@ -486,15 +486,7 @@ GameLib.D3.Mesh.prototype.updateInstance = function() { } if (this.updateRotationFromAxisAngle) { - this.quaternion.axis.instance.x = this.quaternion.axis.x; - this.quaternion.axis.instance.y = this.quaternion.axis.y; - this.quaternion.axis.instance.z = this.quaternion.axis.z; - this.quaternion.instance.setFromAxisAngle(this.quaternion.axis.instance, this.quaternion.angle); - this.instance.quaternion.copy(this.quaternion.instance); - this.quaternion.x = this.quaternion.instance.x; - this.quaternion.y = this.quaternion.instance.y; - this.quaternion.z = this.quaternion.instance.z; - this.quaternion.w = this.quaternion.instance.w; + this.updateInstanceRotationFromAxisAngle(); } else { this.instance.quaternion.x = this.quaternion.x; this.instance.quaternion.y = this.quaternion.y; @@ -809,11 +801,19 @@ GameLib.D3.Mesh.prototype.createInstanceDefaults = function(instance) { instance.position.y = this.position.y; instance.position.z = this.position.z; + instance.quaternion.x = this.quaternion.x; instance.quaternion.y = this.quaternion.y; instance.quaternion.z = this.quaternion.z; instance.quaternion.w = this.quaternion.w; - instance.quaternion.setFromAxisAngle(this.quaternion.axis.instance, this.quaternion.angle); + instance.quaternion.setFromAxisAngle( + new THREE.Vector3( + this.quaternion.axis.x, + this.quaternion.axis.y, + this.quaternion.axis.z + ), + this.quaternion.angle + ); instance.scale.x = this.scale.x; instance.scale.y = this.scale.y; @@ -937,6 +937,18 @@ GameLib.D3.Mesh.prototype.centerAroundOrigin = function() { this.updateInstance(); }; +GameLib.D3.Mesh.prototype.getDistanceFromCenter = function() { + var position = this.instance.geometry.center(); + return new GameLib.Vector3( + this.graphics, + new GameLib.API.Vector3( + position.x, + position.y, + position.z + ) + ) +}; + /** * Applies position, rotation and scale to the object vertice data, resets scale, rotation and sets position to origin. */ @@ -947,31 +959,58 @@ GameLib.D3.Mesh.prototype.applyPositionRotationScale = function() { this.instance.geometry.applyMatrix(this.instance.matrix); this.position.x = 0; - this.position.y = 0; - this.position.z = 0; - this.instance.position.set(0,0,0); + this.position.y = 0; + this.position.z = 0; + this.updateInstancePosition(); this.scale.x = 1; this.scale.y = 1; this.scale.z = 1; this.instance.scale.set(1,1,1); - this.quaternion.axis.x = 0; - this.quaternion.axis.y = 0; - this.quaternion.axis.z = 0; - this.quaternion.axis.w = 1; - this.quaternion.angle = 0; - this.instance.quaternion.setFromAxisAngle(this.quaternion.axis.instance, this.quaternion.angle); - this.quaternion.x = this.instance.quaternion.x; - this.quaternion.y = this.instance.quaternion.y; - this.quaternion.z = this.instance.quaternion.z; - this.quaternion.w = this.instance.quaternion.w; + this.updateInstanceRotationFromAxisAngle( + new GameLib.Vector3( + this.graphics, + new GameLib.API.Vector3( + 0,0,0 + ) + ), + 0 + ); this.instance.updateMatrix(); this.updateVerticesFromGeometryInstance(this.instance.geometry); }; +GameLib.D3.Mesh.prototype.updateInstanceRotationFromAxisAngle = function(axis, angle) { + + if (GameLib.Utils.UndefinedOrNull(axis)) { + axis = this.quaternion.axis; + } + + if (GameLib.Utils.UndefinedOrNull(angle)) { + angle = this.quaternion.angle; + } + + this.quaternion.axis.instance.x = axis.x; + this.quaternion.axis.instance.y = axis.y; + this.quaternion.axis.instance.z = axis.z; + this.quaternion.instance.setFromAxisAngle(this.quaternion.axis.instance, angle); + this.instance.quaternion.copy(this.quaternion.instance); + this.quaternion.x = this.quaternion.instance.x; + this.quaternion.y = this.quaternion.instance.y; + this.quaternion.z = this.quaternion.instance.z; + this.quaternion.w = this.quaternion.instance.w; +}; + +GameLib.D3.Mesh.prototype.updateInstancePosition = function() { + this.position.instance.x = this.position.x; + this.position.instance.y = this.position.y; + this.position.instance.z = this.position.z; + this.instance.position.copy(this.position.instance); +}; + /** * Gets all children components of this Mesh (all linked objects only - no object references i.e. string ids) diff --git a/src/game-lib-system-animation.js b/src/game-lib-system-animation.js index f8244c3..30893cd 100644 --- a/src/game-lib-system-animation.js +++ b/src/game-lib-system-animation.js @@ -44,16 +44,29 @@ GameLib.System.Animation.prototype.start = function() { targetAngle : mesh.quaternion.angle, angleIncrement : true, intermediateAngle : mesh.quaternion.angle, - subscription : null + subscription : null, + inProcess : false, + blocking : animation.blocking, + callbacks : [], + storedValues : [] }; var getIntermediateAngle = function() { return mesh.animationObject.intermediateAngle; }; + var getTargetAngle = function() { + + if (mesh.animationObject.storedValues.length > 0) { + return mesh.animationObject.storedValues[mesh.animationObject.storedValues.length - 1]; + } + + return mesh.animationObject.targetAngle; + }; + var animateRotation = function(value) { - mesh.animationObject.intermediateAngle = value; + mesh.animationObject.intermediateAngle += value; var done = false; @@ -61,7 +74,7 @@ GameLib.System.Animation.prototype.start = function() { /** * We are rotating upwards */ - if (value >= mesh.animationObject.targetAngle) { + if (mesh.animationObject.intermediateAngle >= mesh.animationObject.targetAngle) { /** * We need to stop */ @@ -71,7 +84,7 @@ GameLib.System.Animation.prototype.start = function() { /** * We are rotating downwards */ - if (value <= mesh.animationObject.targetAngle) { + if (mesh.animationObject.intermediateAngle <= mesh.animationObject.targetAngle) { /** * We need to stop */ @@ -81,69 +94,139 @@ GameLib.System.Animation.prototype.start = function() { if (done) { + /** + * We clamp to our target angle + */ + mesh.animationObject.intermediateAngle = mesh.animationObject.targetAngle; + + /** + * We limit our intermediate angle between values of -pi and pi + */ + while (mesh.animationObject.intermediateAngle > Math.PI) { + mesh.animationObject.intermediateAngle -= (Math.PI * 2); + } + + while (mesh.animationObject.intermediateAngle < -(Math.PI)) { + mesh.animationObject.intermediateAngle += (Math.PI * 2); + } + + /** + * We apply our new intermediate angle to our target + */ + mesh.animationObject.targetAngle = mesh.animationObject.intermediateAngle; + } + + /** + * Apply the actual rotation to the mesh + */ + mesh.updateInstanceRotationFromAxisAngle(mesh.quaternion.axis, mesh.animationObject.intermediateAngle); + + /** + * Check again if we are done, we need to do some additional work - + */ + if (done) { + + if (!mesh.animationObject.subscription) { + var message = 'mesh animation object subscription went missing for '; + message += mesh.name + ': '; + message += animation.name; + console.warn(message); + throw new Error(message); + } + /** * Stop subscribing to before render events */ mesh.animationObject.subscription.remove(); /** - * * @type {null} */ mesh.animationObject.subscription = null; /** - * Start checking again for animation requests + * For some meshes, when we are done with the animation, we want to apply + * the current state of the mesh to the object data itself (i.e. update + * its vertices etc) */ - Object.defineProperty( - mesh.quaternion, - 'angle', - { - 'get' : getIntermediateAngle, - 'set' : animationCheck, - 'configurable' : true - } - ); + if (animation.applyToMeshWhenDone) { + /** + * Now we say that our intermediate angle is zero, because we will apply our rotation + * and this will prevent us from re-registering a new 'animationRender' event + */ + mesh.animationObject.targetAngle = 0; + mesh.animationObject.intermediateAngle = 0; + + /** + * Apply our position, rotation and scale to the mesh + */ + mesh.applyPositionRotationScale(); + } /** - * Set our target angle value + * Tell our animation component that it is no longer in process... + * @type {boolean} */ - mesh.animationObject.intermediateAngle = mesh.animationObject.targetAngle; + mesh.animationObject.inProcess = false; - /** - * Update our actual angle - */ - mesh.quaternion.angle = mesh.animationObject.targetAngle; + // if (mesh.animationObject.callbacks.length > 0) { + // var callback = mesh.animationObject.callbacks[0]; + // mesh.animationObject.callbacks.splice(0,1); + // callback(); + // } - /** - * Update our instance - */ - mesh.updateInstance(); - - /** - * Now we say that our intermediate angle is zero, because we will apply our rotation - * and this will prevent us from re-registering a new 'animationRender' event - */ - mesh.animationObject.intermediateAngle = 0; - - /** - * Apply our position, rotation and scale to the mesh - */ - mesh.applyPositionRotationScale(); + mesh.animationObject.storedValues = []; } }; - - var animationCheck = function(value) { + + var setTargetAngle = function(value) { /** * Check if we have work to do */ if (mesh.animationObject.intermediateAngle === value) { + + mesh.animationObject.inProcess = false; + /** * Nothing to do */ return; - } else if (mesh.animationObject.intermediateAngle > value) { + } + + /** + * Check if we have another animation in process + */ + if (mesh.animationObject.inProcess && mesh.animationObject.blocking) { + + console.log('another animation is already in process'); + + GameLib.Utils.PushUnique(mesh.animationObject.storedValues, value); + + // mesh.animationObject.callbacks.push( + // function(__value) { + // return function(){ + // mesh.quaternion.angle = __value; + // } + // }(value) + // ); + + /** + * Respond that our angle is actually our target angle (it will be that soon) + */ + return; + } + + /** + * We indicate that we now have an animation in process + * @type {boolean} + */ + mesh.animationObject.inProcess = true; + + /** + * Ok - all good - lets start the animation + */ + if (mesh.animationObject.intermediateAngle > value) { /** * We will rotate towards by decrementing */ @@ -161,19 +244,6 @@ GameLib.System.Animation.prototype.start = function() { */ mesh.animationObject.targetAngle = value; - /** - * Now override the setter again - */ - Object.defineProperty( - mesh.quaternion, - 'angle', - { - 'get' : getIntermediateAngle, - 'set' : animateRotation, - 'configurable' : true - } - ); - /** * Now we subscribe to 'before render' events, and slowly increment the value * @type {{fn, remove}} @@ -184,17 +254,11 @@ GameLib.System.Animation.prototype.start = function() { var increment = Math.abs(animation.rotationSpeed); - if (mesh.angleIncrement) { + if (!mesh.animationObject.angleIncrement) { increment *= -1; } - mesh.quaternion.angle = (data.delta * increment) + mesh.animationObject.intermediateAngle; - - var backup = mesh.updateRotationFromAxisAngle; - - mesh.updateRotationFromAxisAngle = true; - mesh.updateInstance(); - mesh.updateRotationFromAxisAngle = backup; + animateRotation(data.delta * increment); } ); }; @@ -208,8 +272,8 @@ GameLib.System.Animation.prototype.start = function() { mesh.quaternion, 'angle', { - 'get' : getIntermediateAngle, - 'set' : animationCheck, + 'get' : getTargetAngle, + 'set' : setTargetAngle, 'configurable' : true } );