File:ReversePlayback.js

/**
 * @module EaselJS Animation
 * @namespace springroll.easeljs
 * @requires Core, Animation, EaselJS Display
 */
(function()
{
	var Application = include('springroll.Application');

	/**
	 * Create an update listener that checks plays the animation
	 * in reverse. Requires the animation to have the same labeling
	 * system as the springroll.Animator system.
	 * 	i.e. each animation must have a corresponding ending frame
	 * 	marked with	a '_stop' and '_loop' suffixes,
	 * for instance: "walk" requires "walk_loop"
	 * @class ReversePlayback
	 * @static
	 * @param {createjs.MovieClip} clip
	 * The MovieClip containing the timeline and animation
	 */
	var ReversePlayback = function(clip)
	{
		/**
		 * The animation clip to play
		 * @property {createjs.MovieClip} clip
		 */
		this.clip = clip;

		/**
		 * The framerate which to playback the clip
		 * @property {int} frameRate
		 */
		this.frameRate = 24;

		/**
		 * The list of frame events
		 * @property {object} frameDictionary
		 */
		this.frameDictionary = buildDictionary(clip);

		// Update binding
		this.update = this.update.bind(this);
	};

	// Reference to prototype
	var p = extend(ReversePlayback);

	/**
	 * Build a dictionary of all animations start and end
	 * frame positions'
	 * @method _buildDictionary
	 * @private
	 */
	var buildDictionary = function(clip)
	{
		var str, i, label, dict = {};
		for (i = clip._labels.length - 1; i >= 0; i--)
		{
			label = clip._labels[i];
			str = label.label;
			if (str.indexOf('_stop') > -1 || str.indexOf('_loop') > -1)
			{
				continue;
			}

			if (!dict[str])
			{
				dict[str] = {
					first: label.position,
					last: null
				};
			}
		}

		var stop, loop;
		for (i = clip._labels.length - 1; i >= 0; i--)
		{
			label = clip._labels[i];
			str = label.label;
			stop = str.indexOf('_stop');
			loop = str.indexOf('_loop');
			if (loop > -1)
			{
				dict[str.substring(0, loop)].last = label.position;
			}
		}
		return dict;
	};

	/**
	 * Play the specificied animation
	 * @method  play
	 * @param {string} label
	 */
	p.play = function(label)
	{
		this.stop();

		var frame = this.frameDictionary[label];
		this.startFrame = frame.last;
		this.endFrame = frame.first;
		this.framePassed = this.frameRate;
		this.clip.gotoAndStop(this.endFrame);
		Application.instance.on('update', this.update);
	};

	/**
	 * Go to the previous frame of the animation
	 * @method  goToPreviousFrame
	 */
	p.goToPreviousFrame = function()
	{
		var prevFrame = this.clip.currentFrame - 1;
		if (prevFrame < this.endFrame)
		{
			//loop back to last-frame
			prevFrame = this.startFrame;
		}
		this.clip.gotoAndStop(prevFrame);
	};

	/**
	 * Update the animation when framerate matches animation's framerate
	 * @method  update
	 * @param {number} elapsed Time in milleseconds since last frame update
	 */
	p.update = function(elapsed)
	{
		this.framePassed -= elapsed;
		if (this.framePassed <= 0)
		{
			this.framePassed = this.frameRate;
			this.goToPreviousFrame();
		}
	};

	/**
	 * End the frame update loop
	 * @method stop
	 */
	p.stop = function()
	{
		Application.instance.off('update', this.update);
	};

	//Assign to namespace
	namespace('springroll.easeljs').ReversePlayback = ReversePlayback;
}());