/** * System takes care of updating all the entities (based on their component data) * @param apiSystem GameLib.API.System * @constructor */ GameLib.System.Animation = function( apiSystem ) { GameLib.System.call( this, apiSystem ); }; GameLib.System.Animation.prototype = Object.create(GameLib.System.prototype); GameLib.System.Animation.prototype.constructor = GameLib.System.Animation; GameLib.System.Animation.prototype.start = function() { GameLib.System.prototype.start.call(this); this.animationEntities = GameLib.EntityManager.Instance.findEntities([GameLib.D3.Animation]); this.animationEntities.map( function(animationEntity) { /** * Get all meshes and all animation components */ var meshComponents = animationEntity.getComponents(GameLib.D3.Mesh); var animationComponents = animationEntity.getComponents(GameLib.D3.Animation); animationComponents.map(function(animation){ meshComponents.map(function(mesh){ if (animation.rotationSpeed) { /** * Back up the current property descriptor */ mesh.animationObject = { backupAngleDescriptor : Object.getOwnPropertyDescriptor(mesh.quaternion, 'angle'), targetAngle : mesh.quaternion.angle, angleIncrement : true, intermediateAngle : mesh.quaternion.angle, subscription : null }; var getIntermediateAngle = function() { return mesh.animationObject.intermediateAngle; }; var animateRotation = function(value) { mesh.animationObject.intermediateAngle = value; var done = false; if (mesh.animationObject.angleIncrement) { /** * We are rotating upwards */ if (value >= mesh.animationObject.targetAngle) { /** * We need to stop */ done = true; } } else { /** * We are rotating downwards */ if (value <= mesh.animationObject.targetAngle) { /** * We need to stop */ done = true; } } if (done) { /** * Stop subscribing to before render events */ mesh.animationObject.subscription.remove(); /** * * @type {null} */ mesh.animationObject.subscription = null; /** * Start checking again for animation requests */ Object.defineProperty( mesh.quaternion, 'angle', { 'get' : getIntermediateAngle, 'set' : animationCheck, 'configurable' : true } ); /** * Set our target angle value */ mesh.animationObject.intermediateAngle = mesh.animationObject.targetAngle; /** * Update our actual angle */ mesh.quaternion.angle = mesh.animationObject.targetAngle; /** * 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(); } }; var animationCheck = function(value) { /** * Check if we have work to do */ if (mesh.animationObject.intermediateAngle === value) { /** * Nothing to do */ return; } else if (mesh.animationObject.intermediateAngle > value) { /** * We will rotate towards by decrementing */ mesh.animationObject.angleIncrement = false; } else { /** * We will rotate towards by incrementing */ mesh.animationObject.angleIncrement = true; } /** * We say what our target angle is - when we reach our target angle, we want * to stop our animation */ 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}} */ mesh.animationObject.subscription = GameLib.Event.Subscribe( GameLib.Event.BEFORE_RENDER, function(data) { var increment = Math.abs(animation.rotationSpeed); if (mesh.angleIncrement) { increment *= -1; } mesh.quaternion.angle = (data.delta * increment) + mesh.animationObject.intermediateAngle; var backup = mesh.updateRotationFromAxisAngle; mesh.updateRotationFromAxisAngle = true; mesh.updateInstance(); mesh.updateRotationFromAxisAngle = backup; } ); }; /** * Override the property descriptor - to slowly increment the angle, but report back its * target angle as its actual angle. */ Object.defineProperty( mesh.quaternion, 'angle', { 'get' : getIntermediateAngle, 'set' : animationCheck, 'configurable' : true } ); } }); }); } ); }; /** * Stop Animation System */ GameLib.System.Animation.prototype.stop = function() { GameLib.System.prototype.stop.call(this); this.animationEntities = GameLib.EntityManager.Instance.findEntities([GameLib.D3.Animation]); this.animationEntities.map( function(animationEntity) { /** * Get all meshes and all animation components */ var meshComponents = animationEntity.getComponents(GameLib.D3.Mesh); var animationComponents = animationEntity.getComponents(GameLib.D3.Animation); animationComponents.map( function (animation) { meshComponents.map( function (mesh) { if (animation.rotationSpeed) { if (mesh.animationObject) { if (mesh.animationObject.backupAngleDescriptor) { Object.defineProperty( mesh.quaternion, 'angle', mesh.animationObject.backupAngleDescriptor ) } if (mesh.animationObject.targetAngle) { mesh.quaternion.angle = mesh.animationObject.targetAngle; } if (mesh.animationObject.subscription) { mesh.animationObject.subscription.remove(); } delete mesh.animationObject; } } } ) } ) } ); };