UNPKG

phaser

Version:

A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.

428 lines (365 loc) 12.7 kB
/** * @author Jason Nicholls <nicholls.jason@gmail.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'); var Events = require('../events'); var EaseMap = require('../../../math/easing/EaseMap'); /** * @classdesc * A Camera Rotate effect. * * This effect will rotate the Camera so that the its viewport finishes at the given angle in radians, * over the duration and with the ease specified. * * Camera rotation always takes place based on the Camera viewport. By default, rotation happens * in the center of the viewport. You can adjust this with the `originX` and `originY` properties. * * Rotation influences the rendering of _all_ Game Objects visible by this Camera. However, it does not * rotate the Camera viewport itself, which always remains an axis-aligned rectangle. * * Only the camera is rotates. 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 RotateTo * @memberof Phaser.Cameras.Scene2D.Effects * @constructor * @since 3.23.0 * * @param {Phaser.Cameras.Scene2D.Camera} camera - The camera this effect is acting upon. */ var RotateTo = new Class({ initialize: function RotateTo (camera) { /** * The Camera this effect belongs to. * * @name Phaser.Cameras.Scene2D.Effects.RotateTo#camera * @type {Phaser.Cameras.Scene2D.Camera} * @readonly * @since 3.23.0 */ this.camera = camera; /** * Is this effect actively running? * * @name Phaser.Cameras.Scene2D.Effects.RotateTo#isRunning * @type {boolean} * @readonly * @default false * @since 3.23.0 */ this.isRunning = false; /** * The duration of the effect, in milliseconds. * * @name Phaser.Cameras.Scene2D.Effects.RotateTo#duration * @type {number} * @readonly * @default 0 * @since 3.23.0 */ this.duration = 0; /** * The starting angle to rotate the camera from. * * @name Phaser.Cameras.Scene2D.Effects.RotateTo#source * @type {number} * @since 3.23.0 */ this.source = 0; /** * The constantly updated value based on the force. * * @name Phaser.Cameras.Scene2D.Effects.RotateTo#current * @type {number} * @since 3.23.0 */ this.current = 0; /** * The destination angle in radians to rotate the camera to. * * @name Phaser.Cameras.Scene2D.Effects.RotateTo#destination * @type {number} * @since 3.23.0 */ this.destination = 0; /** * The ease function to use during the Rotate. * * @name Phaser.Cameras.Scene2D.Effects.RotateTo#ease * @type {function} * @since 3.23.0 */ this.ease; /** * If this effect is running this holds the current percentage of the progress, a value between 0 and 1. * * @name Phaser.Cameras.Scene2D.Effects.RotateTo#progress * @type {number} * @since 3.23.0 */ this.progress = 0; /** * Effect elapsed timer. * * @name Phaser.Cameras.Scene2D.Effects.RotateTo#_elapsed * @type {number} * @private * @since 3.23.0 */ this._elapsed = 0; /** * @callback CameraRotateCallback * * @param {Phaser.Cameras.Scene2D.Camera} camera - The camera on which the effect is running. * @param {number} progress - The progress of the effect. A value between 0 and 1. * @param {number} angle - The Camera's new angle in radians. */ /** * This callback is invoked every frame for the duration of the effect. * * @name Phaser.Cameras.Scene2D.Effects.RotateTo#_onUpdate * @type {?CameraRotateCallback} * @private * @default null * @since 3.23.0 */ this._onUpdate; /** * On Complete callback scope. * * @name Phaser.Cameras.Scene2D.Effects.RotateTo#_onUpdateScope * @type {any} * @private * @since 3.23.0 */ this._onUpdateScope; /** * The direction of the rotation. * * @name Phaser.Cameras.Scene2D.Effects.RotateTo#clockwise * @type {boolean} * @since 3.23.0 */ this.clockwise = true; /** * The shortest direction to the target rotation. * * @name Phaser.Cameras.Scene2D.Effects.RotateTo#shortestPath * @type {boolean} * @since 3.23.0 */ this.shortestPath = false; }, /** * This effect will scroll the Camera so that the center of its viewport finishes at the given angle, * over the duration and with the ease specified. * * @method Phaser.Cameras.Scene2D.Effects.RotateTo#start * @fires Phaser.Cameras.Scene2D.Events#ROTATE_START * @fires Phaser.Cameras.Scene2D.Events#ROTATE_COMPLETE * @since 3.23.0 * * @param {number} radians - The destination angle in radians to rotate the Camera viewport to. If the angle is positive then the rotation is clockwise else anticlockwise * @param {boolean} [shortestPath=false] - If shortest path is set to true the camera will rotate in the quickest direction clockwise or anti-clockwise. * @param {number} [duration=1000] - The duration of the effect in milliseconds. * @param {(string|function)} [ease='Linear'] - The ease to use for the Rotate. Can be any of the Phaser Easing constants or a custom function. * @param {boolean} [force=false] - Force the rotation effect to start immediately, even if already running. * @param {CameraRotateCallback} [callback] - This callback will be invoked every frame for the duration of the effect. * It is sent four arguments: A reference to the camera, a progress amount between 0 and 1 indicating how complete the effect is, * the current camera scroll x coordinate and the current camera scroll y coordinate. * @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 (radians, shortestPath, duration, ease, force, callback, context) { if (duration === undefined) { duration = 1000; } if (ease === undefined) { ease = EaseMap.Linear; } if (force === undefined) { force = false; } if (callback === undefined) { callback = null; } if (context === undefined) { context = this.camera.scene; } if (shortestPath === undefined) { shortestPath = false; } this.shortestPath = shortestPath; var tmpDestination = radians; if (radians < 0) { tmpDestination = -1 * radians; this.clockwise = false; } else { this.clockwise = true; } var maxRad = (360 * Math.PI) / 180; tmpDestination = tmpDestination - (Math.floor(tmpDestination / maxRad) * maxRad); var cam = this.camera; if (!force && this.isRunning) { return cam; } this.isRunning = true; this.duration = duration; this.progress = 0; // Starting from this.source = cam.rotation; // Destination this.destination = tmpDestination; // Using this ease if (typeof ease === 'string' && EaseMap.hasOwnProperty(ease)) { this.ease = EaseMap[ease]; } else if (typeof ease === 'function') { this.ease = ease; } this._elapsed = 0; this._onUpdate = callback; this._onUpdateScope = context; if (this.shortestPath) { // The shortest path is true so calculate the quickest direction var cwDist = 0; var acwDist = 0; if (this.destination > this.source) { cwDist = Math.abs(this.destination - this.source); } else { cwDist = (Math.abs(this.destination + maxRad) - this.source); } if (this.source > this.destination) { acwDist = Math.abs(this.source - this.destination); } else { acwDist = (Math.abs(this.source + maxRad) - this.destination); } if (cwDist < acwDist) { this.clockwise = true; } else if (cwDist > acwDist) { this.clockwise = false; } } this.camera.emit(Events.ROTATE_START, this.camera, this, duration, tmpDestination); return cam; }, /** * The main update loop for this effect. Called automatically by the Camera. * * @method Phaser.Cameras.Scene2D.Effects.RotateTo#update * @since 3.23.0 * * @param {number} 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; var progress = Clamp(this._elapsed / this.duration, 0, 1); this.progress = progress; var cam = this.camera; if (this._elapsed < this.duration) { var v = this.ease(progress); this.current = cam.rotation; var distance = 0; var maxRad = (360 * Math.PI) / 180; var target = this.destination; var current = this.current; if (this.clockwise === false) { target = this.current; current = this.destination; } if (target >= current) { distance = Math.abs(target - current); } else { distance = (Math.abs(target + maxRad) - current); } var r = 0; if (this.clockwise) { r = (cam.rotation + (distance * v)); } else { r = (cam.rotation - (distance * v)); } cam.rotation = r; if (this._onUpdate) { this._onUpdate.call(this._onUpdateScope, cam, progress, r); } } else { cam.rotation = this.destination; if (this._onUpdate) { this._onUpdate.call(this._onUpdateScope, cam, progress, this.destination); } this.effectComplete(); } }, /** * Called internally when the effect completes. * * @method Phaser.Cameras.Scene2D.Effects.RotateTo#effectComplete * @since 3.23.0 */ effectComplete: function () { this._onUpdate = null; this._onUpdateScope = null; this.isRunning = false; this.camera.emit(Events.ROTATE_COMPLETE, this.camera, this); }, /** * 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.RotateTo#reset * @since 3.23.0 */ reset: function () { this.isRunning = false; this._onUpdate = null; this._onUpdateScope = null; }, /** * Destroys this effect, releasing it from the Camera. * * @method Phaser.Cameras.Scene2D.Effects.RotateTo#destroy * @since 3.23.0 */ destroy: function () { this.reset(); this.camera = null; this.source = null; this.destination = null; } }); module.exports = RotateTo;