Skip to content

Commit 50de14b

Browse files
authored
Merge pull request phaserjs#3857 from khaleb85/master
Added reverse animation feature (issue: phaserjs#3837)
2 parents d50d8b5 + 2f6f8b2 commit 50de14b

2 files changed

Lines changed: 145 additions & 21 deletions

File tree

src/animations/Animation.js

Lines changed: 66 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,14 @@ var Animation = new Class({
536536
component._yoyo = this.yoyo;
537537
}
538538

539-
component.updateFrame(this.frames[startFrame]);
539+
var frame = this.frames[startFrame];
540+
541+
if (startFrame === 0 && !component.forward)
542+
{
543+
frame = this.getLastFrame();
544+
}
545+
546+
component.updateFrame(frame);
540547
},
541548

542549
/**
@@ -578,16 +585,20 @@ var Animation = new Class({
578585
if (component._yoyo)
579586
{
580587
component.forward = false;
581-
582-
component.updateFrame(frame.prevFrame);
583-
584-
// Delay for the current frame
585-
this.getNextTick(component);
588+
this._updateAndGetNextTick(component, frame.prevFrame);
586589
}
587590
else if (component.repeatCounter > 0)
588591
{
589592
// Repeat (happens before complete)
590-
this.repeatAnimation(component);
593+
594+
if (component._reverse && component.forward)
595+
{
596+
component.forward = false;
597+
}
598+
else
599+
{
600+
this.repeatAnimation(component);
601+
}
591602
}
592603
else
593604
{
@@ -596,12 +607,23 @@ var Animation = new Class({
596607
}
597608
else
598609
{
599-
component.updateFrame(frame.nextFrame);
600-
601-
this.getNextTick(component);
610+
this._updateAndGetNextTick(component, frame.nextFrame);
602611
}
603612
},
604613

614+
/**
615+
* Returns the animation last frame.
616+
*
617+
* @method Phaser.Animations.Animation#getLastFrame
618+
* @since 3.12.0
619+
*
620+
* @return {Phaser.Animations.AnimationFrame} component - The Animation Last Frame.
621+
*/
622+
getLastFrame: function ()
623+
{
624+
return this.frames[this.frames.length - 1];
625+
},
626+
605627
/**
606628
* [description]
607629
*
@@ -620,10 +642,24 @@ var Animation = new Class({
620642
{
621643
// We're at the start of the animation
622644

623-
if (component.repeatCounter > 0)
645+
if (component._yoyo)
624646
{
625-
// Repeat (happens before complete)
626-
this.repeatAnimation(component);
647+
component.forward = true;
648+
this._updateAndGetNextTick(component, frame.nextFrame);
649+
}
650+
else if (component.repeatCounter > 0)
651+
{
652+
if (component._reverse && !component.forward)
653+
{
654+
component.currentFrame = this.getLastFrame();
655+
this._updateAndGetNextTick(component, component.currentFrame);
656+
}
657+
else
658+
{
659+
// Repeat (happens before complete)
660+
component.forward = true;
661+
this.repeatAnimation(component);
662+
}
627663
}
628664
else
629665
{
@@ -632,12 +668,25 @@ var Animation = new Class({
632668
}
633669
else
634670
{
635-
component.updateFrame(frame.prevFrame);
636-
637-
this.getNextTick(component);
671+
this._updateAndGetNextTick(component, frame.prevFrame);
638672
}
639673
},
640674

675+
/**
676+
* Update Frame and Wait next tick
677+
*
678+
* @method Phaser.Animations.Animation#_updateAndGetNextTick
679+
* @since 3.12.0
680+
*
681+
* @param {Phaser.Animations.AnimationFrame} frame - An Animation frame
682+
*
683+
*/
684+
_updateAndGetNextTick: function (component, frame)
685+
{
686+
component.updateFrame(frame);
687+
this.getNextTick(component);
688+
},
689+
641690
/**
642691
* [description]
643692
*
@@ -705,9 +754,7 @@ var Animation = new Class({
705754
{
706755
component.repeatCounter--;
707756

708-
component.forward = true;
709-
710-
component.updateFrame(component.currentFrame.nextFrame);
757+
component.updateFrame(component.currentFrame[(component.forward) ? 'nextFrame' : 'prevFrame']);
711758

712759
if (component.isPlaying)
713760
{

src/gameobjects/components/Animation.js

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ var Animation = new Class({
208208
this._yoyo = false;
209209

210210
/**
211-
* Will the playhead move forwards (`true`) or in reverse (`false`)
211+
* Will the playhead move forwards (`true`) or in reverse (`false`).
212212
*
213213
* @name Phaser.GameObjects.Components.Animation#forward
214214
* @type {boolean}
@@ -217,6 +217,17 @@ var Animation = new Class({
217217
*/
218218
this.forward = true;
219219

220+
/**
221+
* An Internal trigger that's play the animation in reverse mode ('true') or not ('false'),
222+
* needed because forward can be changed by yoyo feature.
223+
*
224+
* @name Phaser.GameObjects.Components.Animation#forward
225+
* @type {boolean}
226+
* @default false
227+
* @since 3.12.0
228+
*/
229+
this._reverse = false;
230+
220231
/**
221232
* Internal time overflow accumulator.
222233
*
@@ -496,6 +507,54 @@ var Animation = new Class({
496507
return this.parent;
497508
}
498509

510+
this.forward = true;
511+
this._reverse = false;
512+
return this._startAnimation(key, startFrame);
513+
},
514+
515+
/**
516+
* Plays an Animation (in reverse mode) on the Game Object that owns this Animation Component.
517+
*
518+
* @method Phaser.GameObjects.Components.Animation#playReverse
519+
* @fires Phaser.GameObjects.Components.Animation#onStartEvent
520+
* @since 3.12.0
521+
*
522+
* @param {string} key - The string-based key of the animation to play, as defined previously in the Animation Manager.
523+
* @param {boolean} [ignoreIfPlaying=false] - If an animation is already playing then ignore this call.
524+
* @param {integer} [startFrame=0] - Optionally start the animation playing from this frame index.
525+
*
526+
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
527+
*/
528+
playReverse: function (key, ignoreIfPlaying, startFrame)
529+
{
530+
if (ignoreIfPlaying === undefined) { ignoreIfPlaying = false; }
531+
if (startFrame === undefined) { startFrame = 0; }
532+
533+
if (ignoreIfPlaying && this.isPlaying && this.currentAnim.key === key)
534+
{
535+
return this.parent;
536+
}
537+
538+
this.forward = false;
539+
this._reverse = true;
540+
return this._startAnimation(key, startFrame);
541+
},
542+
543+
/**
544+
* Load an Animation and fires 'onStartEvent' event,
545+
* extracted from 'play' method
546+
*
547+
* @method Phaser.GameObjects.Components.Animation#_startAnimation
548+
* @fires Phaser.GameObjects.Components.Animation#onStartEvent
549+
* @since 3.12.0
550+
*
551+
* @param {string} key - The string-based key of the animation to play, as defined previously in the Animation Manager.
552+
* @param {integer} [startFrame=0] - Optionally start the animation playing from this frame index.
553+
*
554+
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
555+
*/
556+
_startAnimation: function (key, startFrame)
557+
{
499558
this.load(key, startFrame);
500559

501560
var anim = this.currentAnim;
@@ -506,7 +565,6 @@ var Animation = new Class({
506565

507566
anim.getFirstTick(this);
508567

509-
this.forward = true;
510568
this.isPlaying = true;
511569
this.pendingRepeat = false;
512570

@@ -520,6 +578,25 @@ var Animation = new Class({
520578
return gameObject;
521579
},
522580

581+
/**
582+
* Reverse an Animation that is already playing on the Game Object.
583+
*
584+
* @method Phaser.GameObjects.Components.Animation#reverse
585+
* @since 3.12.0
586+
*
587+
* @param {string} key - The string-based key of the animation to play, as defined previously in the Animation Manager.
588+
*
589+
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
590+
*/
591+
reverse: function (key)
592+
{
593+
if (!this.isPlaying || this.currentAnim.key !== key) { return this.parent; }
594+
this._reverse = !this._reverse;
595+
this.forward = !this.forward;
596+
597+
return this.parent;
598+
},
599+
523600
/**
524601
* Returns a value between 0 and 1 indicating how far this animation is through, ignoring repeats and yoyos.
525602
* If the animation has a non-zero repeat defined, `getProgress` and `getTotalProgress` will be different

0 commit comments

Comments
 (0)