phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.
317 lines (268 loc) • 9.72 kB
JavaScript
/**
* @author Richard Davey <rich@phaser.io>
* @copyright 2013-2025 Phaser Studio Inc.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var BaseTweenData = require('./BaseTweenData');
var Clamp = require('../../math/Clamp');
var Class = require('../../utils/Class');
var Events = require('../events');
/**
* @classdesc
* The TweenFrameData is a class that contains a single target that will change the texture frame
* at the conclusion of the Tween.
*
* TweenFrameData instances are typically created by the TweenBuilder automatically, when it
* detects the presence of a 'texture' property as the key being tweened.
*
* A Tween can own multiple TweenFrameData instances, but a TweenFrameData only
* ever belongs to a single Tween.
*
* You should not typically create these yourself, but rather use the TweenBuilder,
* or the `Tween.addFrame` method.
*
* @class TweenFrameData
* @memberof Phaser.Tweens
* @extends Phaser.Tweens.BaseTweenData
* @constructor
* @since 3.60.0
*
* @param {Phaser.Tweens.Tween} tween - The tween this TweenData instance belongs to.
* @param {number} targetIndex - The target index within the Tween targets array.
* @param {string} texture - The texture key to set at the end of this tween.
* @param {(string|number)} frame - The texture frame to set at the end of this tween.
* @param {function} delay - Function that returns the time in milliseconds before tween will start.
* @param {number} duration - The duration of the tween in milliseconds.
* @param {number} hold - Function that returns the time in milliseconds the tween will pause before repeating or returning to its starting value if yoyo is set to true.
* @param {number} repeat - Function that returns the number of times to repeat the tween. The tween will always run once regardless, so a repeat value of '1' will play the tween twice.
* @param {number} repeatDelay - Function that returns the time in milliseconds before the repeat will start.
* @param {boolean} flipX - Should toggleFlipX be called when yoyo or repeat happens?
* @param {boolean} flipY - Should toggleFlipY be called when yoyo or repeat happens?
*/
var TweenFrameData = new Class({
Extends: BaseTweenData,
initialize:
function TweenFrameData (tween, targetIndex, texture, frame, delay, duration, hold, repeat, repeatDelay, flipX, flipY)
{
BaseTweenData.call(this, tween, targetIndex, delay, duration, false, hold, repeat, repeatDelay, flipX, flipY);
/**
* The property of the target to be tweened.
*
* Always 'texture' for a TweenFrameData object.
*
* @name Phaser.Tweens.TweenFrameData#key
* @type {string}
* @readonly
* @since 3.60.0
*/
this.key = 'texture';
/**
* The texture to be set at the start of the tween.
*
* @name Phaser.Tweens.TweenFrameData#startTexture
* @type {string}
* @since 3.60.0
*/
this.startTexture = null;
/**
* The texture to be set at the end of the tween.
*
* @name Phaser.Tweens.TweenFrameData#endTexture
* @type {string}
* @since 3.60.0
*/
this.endTexture = texture;
/**
* The frame to be set at the start of the tween.
*
* @name Phaser.Tweens.TweenFrameData#startFrame
* @type {(string|number)}
* @since 3.60.0
*/
this.startFrame = null;
/**
* The frame to be set at the end of the tween.
*
* @name Phaser.Tweens.TweenFrameData#endFrame
* @type {(string|number)}
* @since 3.60.0
*/
this.endFrame = frame;
/**
* Will the Tween ease back to its starting values, after reaching the end
* and any `hold` value that may be set?
*
* @name Phaser.Tweens.TweenFrameData#yoyo
* @type {boolean}
* @since 3.60.0
*/
this.yoyo = (repeat !== 0) ? true : false;
},
/**
* Internal method that resets this Tween Data entirely, including the progress and elapsed values.
*
* Called automatically by the parent Tween. Should not be called directly.
*
* @method Phaser.Tweens.TweenFrameData#reset
* @since 3.60.0
*
* @param {boolean} [isSeeking=false] - Is the Tween Data being reset as part of a Tween seek?
*/
reset: function (isSeeking)
{
BaseTweenData.prototype.reset.call(this);
var target = this.tween.targets[this.targetIndex];
if (!this.startTexture)
{
this.startTexture = target.texture.key;
this.startFrame = target.frame.name;
}
if (isSeeking)
{
target.setTexture(this.startTexture, this.startFrame);
}
},
/**
* Internal method that advances this TweenData based on the delta value given.
*
* @method Phaser.Tweens.TweenFrameData#update
* @fires Phaser.Tweens.Events#TWEEN_UPDATE
* @fires Phaser.Tweens.Events#TWEEN_REPEAT
* @since 3.60.0
*
* @param {number} delta - The elapsed delta time in ms.
*
* @return {boolean} `true` if this TweenData is still playing, or `false` if it has finished entirely.
*/
update: function (delta)
{
var tween = this.tween;
var targetIndex = this.targetIndex;
var target = tween.targets[targetIndex];
// Bail out if we don't have a target to act upon
if (!target)
{
this.setCompleteState();
return false;
}
if (this.isCountdown)
{
this.elapsed -= delta;
if (this.elapsed <= 0)
{
this.elapsed = 0;
delta = 0;
if (this.isDelayed())
{
this.setPendingRenderState();
}
else if (this.isRepeating())
{
this.setPlayingForwardState();
this.dispatchEvent(Events.TWEEN_REPEAT, 'onRepeat');
}
else if (this.isHolding())
{
this.setStateFromEnd(0);
}
}
}
// All of the above have the ability to change the state, so put this in its own check
if (this.isPendingRender())
{
if (this.startTexture)
{
target.setTexture(this.startTexture, this.startFrame);
}
this.setPlayingForwardState();
return true;
}
var forward = this.isPlayingForward();
var backward = this.isPlayingBackward();
if (forward || backward)
{
var elapsed = this.elapsed;
var duration = this.duration;
var diff = 0;
var complete = false;
elapsed += delta;
if (elapsed >= duration)
{
diff = elapsed - duration;
elapsed = duration;
complete = true;
}
else if (elapsed < 0)
{
elapsed = 0;
}
var progress = Clamp(elapsed / duration, 0, 1);
this.elapsed = elapsed;
this.progress = progress;
if (complete)
{
if (forward)
{
target.setTexture(this.endTexture, this.endFrame);
if (this.hold > 0)
{
this.elapsed = this.hold;
this.setHoldState();
}
else
{
this.setStateFromEnd(diff);
}
}
else
{
target.setTexture(this.startTexture, this.startFrame);
this.setStateFromStart(diff);
}
}
this.dispatchEvent(Events.TWEEN_UPDATE, 'onUpdate');
}
// Return TRUE if this TweenData still playing, otherwise FALSE
return !this.isComplete();
},
/**
* Internal method that will emit a TweenData based Event on the
* parent Tween and also invoke the given callback, if provided.
*
* @method Phaser.Tweens.TweenFrameData#dispatchEvent
* @since 3.60.0
*
* @param {Phaser.Types.Tweens.Event} event - The Event to be dispatched.
* @param {Phaser.Types.Tweens.TweenCallbackTypes} [callback] - The name of the callback to be invoked. Can be `null` or `undefined` to skip invocation.
*/
dispatchEvent: function (event, callback)
{
var tween = this.tween;
if (!tween.isSeeking)
{
var target = tween.targets[this.targetIndex];
var key = this.key;
tween.emit(event, tween, key, target);
var handler = tween.callbacks[callback];
if (handler)
{
handler.func.apply(tween.callbackScope, [ tween, target, key ].concat(handler.params));
}
}
},
/**
* Immediately destroys this TweenData, nulling of all its references.
*
* @method Phaser.Tweens.TweenFrameData#destroy
* @since 3.60.0
*/
destroy: function ()
{
BaseTweenData.prototype.destroy.call(this);
this.startTexture = null;
this.endTexture = null;
this.startFrame = null;
this.endFrame = null;
}
});
module.exports = TweenFrameData;