New Camera Shake effect class

This commit is contained in:
Richard Davey 2018-04-14 12:35:39 +01:00
parent a56465fdad
commit 1a51e859dd

View file

@ -0,0 +1,321 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
var Clamp = require('../../../math/Clamp');
var Class = require('../../../utils/Class');
/**
* @classdesc
* A Camera Shake effect.
*
* This effect will shake the camera viewport by a random amount, bounded by the specified intensity, each frame.
*
* Only the camera viewport is moved. None of the objects it is displaying are impacted, i.e. their positions do
* not change.
*
* The effect will dispatch several events on the Camera itself and you can also specify an `onUpdate` callback,
* which is invoked each frame for the duration of the effect if required.
*
* @class Shake
* @memberOf Phaser.Cameras.Scene2D.Effects
* @constructor
* @since 3.5.0
*
* @param {Phaser.Cameras.Scene2D.Camera} camera - The camera this effect is acting upon.
*/
var Shake = new Class({
initialize:
function Shake (camera)
{
/**
* The Camera this effect belongs to.
*
* @name Phaser.Cameras.Scene2D.Effects.Shake#camera
* @type {Phaser.Cameras.Scene2D.Camera}
* @readOnly
* @since 3.5.0
*/
this.camera = camera;
/**
* Is this effect actively running?
*
* @name Phaser.Cameras.Scene2D.Effects.Shake#isRunning
* @type {boolean}
* @readOnly
* @default false
* @since 3.5.0
*/
this.isRunning = false;
/**
* The duration of the effect, in milliseconds.
*
* @name Phaser.Cameras.Scene2D.Effects.Shake#duration
* @type {integer}
* @readOnly
* @default 0
* @since 3.5.0
*/
this.duration = 0;
/**
* The intensity of the effect. Use small float values.
* The default when the effect starts is 0.05.
* You can modify this value while the effect is active to create
* more varied shake effects.
*
* @name Phaser.Cameras.Scene2D.Effects.Shake#intensity
* @type {float}
* @default 0
* @since 3.5.0
*/
this.intensity = 0;
/**
* If this effect is running this holds the current percentage of the progress, a value between 0 and 1.
*
* @name Phaser.Cameras.Scene2D.Effects.Shake#progress
* @type {float}
* @since 3.5.0
*/
this.progress = 0;
/**
* Effect elapsed timer.
*
* @name Phaser.Cameras.Scene2D.Effects.Shake#_elapsed
* @type {number}
* @private
* @since 3.5.0
*/
this._elapsed = 0;
/**
* How much to offset the camera by horizontally.
*
* @name Phaser.Cameras.Scene2D.Effects.Shake#_offsetX
* @type {number}
* @private
* @default 0
* @since 3.0.0
*/
this._offsetX = 0;
/**
* How much to offset the camera by vertically.
*
* @name Phaser.Cameras.Scene2D.Effects.Shake#_offsetY
* @type {number}
* @private
* @default 0
* @since 3.0.0
*/
this._offsetY = 0;
/**
* This callback is invoked every frame for the duration of the effect.
*
* @name Phaser.Cameras.Scene2D.Effects.Shake#_onUpdate
* @type {?Camera2DCallback}
* @private
* @default null
* @since 3.5.0
*/
this._onUpdate;
/**
* On Complete callback scope.
*
* @name Phaser.Cameras.Scene2D.Effects.Shake#_onUpdateScope
* @type {any}
* @private
* @since 3.5.0
*/
this._onUpdateScope;
},
/**
* This event is fired when the shake effect begins to run on a camera.
*
* @event CameraShakeStartEvent
* @param {Phaser.Cameras.Scene2D.Camera} camera - The camera that the effect began on.
* @param {Phaser.Cameras.Scene2D.Effects.Shake} effect - A reference to the effect instance.
* @param {integer} duration - The duration of the effect.
* @param {float} intensity - The intensity of the effect.
*/
/**
* This event is fired when the shake effect completes.
*
* @event CameraShakeCompleteEvent
* @param {Phaser.Cameras.Scene2D.Camera} camera - The camera that the effect began on.
* @param {Phaser.Cameras.Scene2D.Effects.Shake} effect - A reference to the effect instance.
*/
/**
* Shakes the Camera by the given intensity over the duration specified.
*
* @method Phaser.Cameras.Scene2D.Effects.Shake#start
* @fires CameraShakeStartEvent
* @fires CameraShakeCompleteEvent
* @since 3.5.0
*
* @param {number} duration - The duration of the effect in milliseconds.
* @param {number} [intensity=0.05] - The intensity of the shake.
* @param {boolean} [force=false] - Force the shake effect to start immediately, even if already running.
* @param {function} [callback] - This callback will be invoked every frame for the duration of the effect.
* It is sent two arguments: A reference to the camera and a progress amount between 0 and 1 indicating how complete the effect is.
* @param {any} [context] - The context in which the callback is invoked. Defaults to the Scene to which the Camera belongs.
*
* @return {Phaser.Cameras.Scene2D.Camera} The Camera on which the effect was started.
*/
start: function (duration, intensity, force, callback, context)
{
if (!duration) { duration = Number.MIN_VALUE; }
if (intensity === undefined) { intensity = 0.05; }
if (force === undefined) { force = false; }
if (callback === undefined) { callback = null; }
if (context === undefined) { context = this.camera.scene; }
if (!force && this.isRunning)
{
return this.camera;
}
this.isRunning = true;
this.duration = duration;
this.intensity = intensity;
this.progress = 0;
this._elapsed = 0;
this._offsetX = 0;
this._offsetY = 0;
this._onUpdate = callback;
this._onUpdateScope = context;
this.camera.emit('camerashakestart', this.camera, this, duration, intensity);
return this.camera;
},
/**
* The pre-render step for this effect. Called automatically by the Camera.
*
* @method Phaser.Cameras.Scene2D.Effects.Shake#preRender
* @since 3.5.0
*/
preRender: function ()
{
if (this.isRunning)
{
this.camera.matrix.translate(this._offsetX, this._offsetY);
}
},
/**
* The main update loop for this effect. Called automatically by the Camera.
*
* @method Phaser.Cameras.Scene2D.Effects.Shake#update
* @since 3.5.0
*
* @param {integer} time - The current timestamp as generated by the Request Animation Frame or SetTimeout.
* @param {number} delta - The delta time, in ms, elapsed since the last frame.
*/
update: function (time, delta)
{
if (!this.isRunning)
{
return;
}
this._elapsed += delta;
this.progress = Clamp(this._elapsed / this.duration, 0, 1);
if (this._onUpdate)
{
this._onUpdate.call(this._onUpdateScope, this.camera, this.progress);
}
if (this._elapsed < this.duration)
{
var intensity = this.intensity;
var width = this.camera.width;
var height = this.camera.height;
var zoom = this.camera.zoom;
this._offsetX = (Math.random() * intensity * width * 2 - intensity * width) * zoom;
this._offsetY = (Math.random() * intensity * height * 2 - intensity * height) * zoom;
if (this.camera.roundPixels)
{
this._offsetX |= 0;
this._offsetY |= 0;
}
}
else
{
this.effectComplete();
}
},
/**
* Called internally when the effect completes.
*
* @method Phaser.Cameras.Scene2D.Effects.Shake#effectComplete
* @since 3.5.0
*/
effectComplete: function ()
{
this._offsetX = 0;
this._offsetY = 0;
this._onUpdate = null;
this._onUpdateScope = null;
this.isRunning = false;
this.camera.emit('camerashakecomplete', this, this.camera);
},
/**
* Resets this camera effect.
* If it was previously running, it stops instantly without calling its onComplete callback or emitting an event.
*
* @method Phaser.Cameras.Scene2D.Effects.Shake#reset
* @since 3.5.0
*/
reset: function ()
{
this.isRunning = false;
this._offsetX = 0;
this._offsetY = 0;
this._onUpdate = null;
this._onUpdateScope = null;
},
/**
* Destroys this effect, releasing it from the Camera.
*
* @method Phaser.Cameras.Scene2D.Effects.Shake#destroy
* @since 3.5.0
*/
destroy: function ()
{
this.reset();
this.camera = null;
}
});
module.exports = Shake;