diff --git a/starling/src/starling/display/MovieClip.as b/starling/src/starling/display/MovieClip.as
index b46dc51e7..7e196c4ff 100644
--- a/starling/src/starling/display/MovieClip.as
+++ b/starling/src/starling/display/MovieClip.as
@@ -52,7 +52,9 @@ package starling.display
private var mCurrentTime:Number;
private var mCurrentFrame:int;
private var mLoop:Boolean;
+ private var mBounceLoop:Boolean;
private var mPlaying:Boolean;
+ private var mPlaybackDir:int;
/** Creates a movie clip from the provided textures and with the specified default framerate.
* The movie will have the size of the first frame. */
@@ -77,6 +79,8 @@ package starling.display
mDefaultFrameDuration = 1.0 / fps;
mLoop = true;
mPlaying = true;
+ mBounceLoop = false;
+ mPlaybackDir = 1;
mCurrentTime = 0.0;
mCurrentFrame = 0;
mTextures = textures.concat();
@@ -211,76 +215,139 @@ package starling.display
// IAnimatable
/** @inheritDoc */
- public function advanceTime(passedTime:Number):void
- {
- if (!mPlaying || passedTime <= 0.0) return;
-
- var finalFrame:int;
- var previousFrame:int = mCurrentFrame;
- var restTime:Number = 0.0;
- var breakAfterFrame:Boolean = false;
- var hasCompleteListener:Boolean = hasEventListener(Event.COMPLETE);
- var dispatchCompleteEvent:Boolean = false;
- var totalTime:Number = this.totalTime;
-
- if (mLoop && mCurrentTime >= totalTime)
- {
- mCurrentTime = 0.0;
- mCurrentFrame = 0;
- }
-
- if (mCurrentTime < totalTime)
- {
- mCurrentTime += passedTime;
- finalFrame = mTextures.length - 1;
-
- while (mCurrentTime > mStartTimes[mCurrentFrame] + mDurations[mCurrentFrame])
- {
- if (mCurrentFrame == finalFrame)
- {
- if (mLoop && !hasCompleteListener)
- {
- mCurrentTime -= totalTime;
- mCurrentFrame = 0;
- }
- else
- {
- breakAfterFrame = true;
- restTime = mCurrentTime - totalTime;
- dispatchCompleteEvent = hasCompleteListener;
- mCurrentFrame = finalFrame;
- mCurrentTime = totalTime;
- }
- }
- else
- {
- mCurrentFrame++;
- }
-
- var sound:Sound = mSounds[mCurrentFrame];
- if (sound) sound.play();
- if (breakAfterFrame) break;
- }
-
- // special case when we reach *exactly* the total time.
- if (mCurrentFrame == finalFrame && mCurrentTime == totalTime)
- dispatchCompleteEvent = hasCompleteListener;
- }
-
- if (mCurrentFrame != previousFrame)
- texture = mTextures[mCurrentFrame];
-
- if (dispatchCompleteEvent)
- dispatchEventWith(Event.COMPLETE);
-
- if (mLoop && restTime > 0.0)
- advanceTime(restTime);
- }
-
+ public function advanceTime(passedTime:Number):void
+ {
+ if (!mPlaying || passedTime <= 0.0) return;
+
+ var finalFrame:int = mTextures.length - 1;
+ var previousFrame:int = mCurrentFrame;
+ var restTime:Number = 0.0;
+ var breakAfterFrame:Boolean = false;
+ var hasCompleteListener:Boolean = hasEventListener(Event.COMPLETE);
+ var dispatchCompleteEvent:Boolean = false;
+ var totalTime:Number = this.totalTime;
+ var sound:Sound;
+
+ if (mLoop)
+ {
+ if (mPlaybackDir == 1 && mCurrentTime >= totalTime)
+ {
+ mCurrentTime = 0.0;
+ mCurrentFrame = 0;
+ }
+ else if (mPlaybackDir == -1 && mCurrentTime == 0)
+ {
+ mCurrentTime = totalTime;
+ mCurrentFrame = mTextures.length - 1;
+ }
+ }
+
+ // forward playback
+ if (mPlaybackDir == 1 && mCurrentTime < totalTime)
+ {
+ mCurrentTime += passedTime;
+
+ while (mCurrentTime > mStartTimes[mCurrentFrame] + mDurations[mCurrentFrame])
+ {
+ if (mCurrentFrame == finalFrame)
+ {
+ if (mLoop && !hasCompleteListener)
+ {
+ mCurrentTime -= totalTime;
+ mCurrentFrame = 0;
+ }
+ else
+ {
+ if (mBounceLoop)
+ {
+ mPlaybackDir = -1;
+ mCurrentTime = mStartTimes[mCurrentFrame];
+ }
+ else
+ {
+ mCurrentTime = totalTime;
+ }
+ breakAfterFrame = true;
+ restTime = mCurrentTime - totalTime;
+ dispatchCompleteEvent = hasCompleteListener;
+ mCurrentFrame = finalFrame;
+ }
+ }
+ else
+ {
+ mCurrentFrame++;
+ }
+
+ sound = mSounds[mCurrentFrame];
+ if (sound) sound.play();
+ if (breakAfterFrame) break;
+ }
+
+ // special case when we reach *exactly* the total time.
+ if (mCurrentFrame == finalFrame && mCurrentTime == totalTime)
+ dispatchCompleteEvent = hasCompleteListener;
+ }
+
+ // reverse playback
+ else if (mPlaybackDir == -1 && mCurrentTime > 0)
+ {
+ mCurrentTime -= passedTime;
+
+ while (mCurrentTime <= mStartTimes[mCurrentFrame])
+ {
+ if (mCurrentFrame == 0)
+ {
+ if (mLoop && !hasCompleteListener)
+ {
+ mCurrentTime += totalTime;
+ mCurrentFrame = finalFrame;
+ }
+ else
+ {
+ if (mBounceLoop)
+ {
+ mPlaybackDir = 1;
+ mCurrentTime = mStartTimes[1];
+ }
+ else
+ {
+ mCurrentTime = 0;
+ }
+ breakAfterFrame = true;
+ restTime = -mCurrentTime;
+ dispatchCompleteEvent = hasCompleteListener;
+ mCurrentFrame = 0;
+ }
+ }
+ else
+ {
+ mCurrentFrame--;
+ }
+
+ sound = mSounds[mCurrentFrame];
+ if (sound) sound.play();
+ if (breakAfterFrame) break;
+ }
+
+ // special case when we reach *exactly* the start time.
+ if (mCurrentFrame == 0 && mCurrentTime == 0)
+ dispatchCompleteEvent = hasCompleteListener;
+ }
+
+ if (mCurrentFrame != previousFrame)
+ texture = mTextures[mCurrentFrame];
+
+ if (dispatchCompleteEvent)
+ dispatchEventWith(Event.COMPLETE);
+
+ if ((mLoop || mBounceLoop) && restTime)
+ advanceTime(restTime);
+ }
+
/** Indicates if a (non-looping) movie has come to its end. */
public function get isComplete():Boolean
{
- return !mLoop && mCurrentTime >= totalTime;
+ return !mLoop && !mBounceLoop && mCurrentTime >= totalTime;
}
// properties
@@ -298,9 +365,45 @@ package starling.display
/** The total number of frames. */
public function get numFrames():int { return mTextures.length; }
- /** Indicates if the clip should loop. */
+ /** Indicates if the clip should loop in one direction.
+ * If set to true
bounceLoop will become false
. */
public function get loop():Boolean { return mLoop; }
- public function set loop(value:Boolean):void { mLoop = value; }
+ public function set loop(value:Boolean):void
+ {
+ mLoop = value;
+ if (mLoop) mBounceLoop = false;
+ }
+
+ /** Indicates if the clip should loop forward and backward.
+ * If set to true
loop will become false
. */
+ public function get bounceLoop():Boolean { return mBounceLoop; }
+ public function set bounceLoop(value:Boolean):void
+ {
+ mBounceLoop = value;
+ if (mBounceLoop) mLoop = false;
+ }
+
+ /** Indicates if the clip will play forward or in reverse.
+ * If the clip is at the end of playback in its current direction,
+ * and playback direction is reversed, playback will restart. */
+ public function get reverse():Boolean { return mPlaybackDir == -1; }
+ public function set reverse(value:Boolean):void
+ {
+ if ((value && mPlaybackDir == -1) || (!value && mPlaybackDir == 1)) return;
+ mPlaybackDir = value ? -1 : 1;
+
+ // if already at the end of playback when reverse is set, restart playback
+ if (mPlaybackDir == 1 && mCurrentTime == totalTime)
+ {
+ mCurrentTime = 0.0;
+ mCurrentFrame = 0;
+ }
+ else if (mPlaybackDir == -1 && mCurrentTime == 0)
+ {
+ mCurrentTime = totalTime;
+ mCurrentFrame = mTextures.length - 1;
+ }
+ }
/** The index of the frame that is currently displayed. */
public function get currentFrame():int { return mCurrentFrame; }
@@ -343,9 +446,12 @@ package starling.display
public function get isPlaying():Boolean
{
if (mPlaying)
- return mLoop || mCurrentTime < totalTime;
- else
- return false;
+ {
+ if (mLoop || mBounceLoop) return true;
+ else if (mPlaybackDir == 1 && mCurrentTime < totalTime) return true;
+ else if (mPlaybackDir == -1 && mCurrentTime > 0) return true;
+ }
+ return false;
}
}
}
\ No newline at end of file