-
Notifications
You must be signed in to change notification settings - Fork 7.1k
/
AnimationState.js
2007 lines (1779 loc) · 66 KB
/
AnimationState.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2013-2023 Photon Storm Ltd.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var Animation = require('./Animation');
var Between = require('../math/Between');
var Class = require('../utils/Class');
var CustomMap = require('../structs/Map');
var Events = require('./events');
var GetFastValue = require('../utils/object/GetFastValue');
/**
* @classdesc
* The Animation State Component.
*
* This component provides features to apply animations to Game Objects. It is responsible for
* loading, queuing animations for later playback, mixing between animations and setting
* the current animation frame to the Game Object that owns this component.
*
* This component lives as an instance within any Game Object that has it defined, such as Sprites.
*
* You can access its properties and methods via the `anims` property, i.e. `Sprite.anims`.
*
* As well as playing animations stored in the global Animation Manager, this component
* can also create animations that are stored locally within it. See the `create` method
* for more details.
*
* Prior to Phaser 3.50 this component was called just `Animation` and lived in the
* `Phaser.GameObjects.Components` namespace. It was renamed to `AnimationState`
* in 3.50 to help better identify its true purpose when browsing the documentation.
*
* @class AnimationState
* @memberof Phaser.Animations
* @constructor
* @since 3.0.0
*
* @param {Phaser.GameObjects.GameObject} parent - The Game Object to which this animation component belongs.
*/
var AnimationState = new Class({
initialize:
function AnimationState (parent)
{
/**
* The Game Object to which this animation component belongs.
*
* You can typically access this component from the Game Object
* via the `this.anims` property.
*
* @name Phaser.Animations.AnimationState#parent
* @type {Phaser.GameObjects.GameObject}
* @since 3.0.0
*/
this.parent = parent;
/**
* A reference to the global Animation Manager.
*
* @name Phaser.Animations.AnimationState#animationManager
* @type {Phaser.Animations.AnimationManager}
* @since 3.0.0
*/
this.animationManager = parent.scene.sys.anims;
this.animationManager.on(Events.REMOVE_ANIMATION, this.globalRemove, this);
/**
* A reference to the Texture Manager.
*
* @name Phaser.Animations.AnimationState#textureManager
* @type {Phaser.Textures.TextureManager}
* @protected
* @since 3.50.0
*/
this.textureManager = this.animationManager.textureManager;
/**
* The Animations stored locally in this Animation component.
*
* Do not modify the contents of this Map directly, instead use the
* `add`, `create` and `remove` methods of this class instead.
*
* @name Phaser.Animations.AnimationState#anims
* @type {Phaser.Structs.Map.<string, Phaser.Animations.Animation>}
* @protected
* @since 3.50.0
*/
this.anims = null;
/**
* Is an animation currently playing or not?
*
* @name Phaser.Animations.AnimationState#isPlaying
* @type {boolean}
* @default false
* @since 3.0.0
*/
this.isPlaying = false;
/**
* Has the current animation started playing, or is it waiting for a delay to expire?
*
* @name Phaser.Animations.AnimationState#hasStarted
* @type {boolean}
* @default false
* @since 3.50.0
*/
this.hasStarted = false;
/**
* The current Animation loaded into this Animation component.
*
* Will by `null` if no animation is yet loaded.
*
* @name Phaser.Animations.AnimationState#currentAnim
* @type {?Phaser.Animations.Animation}
* @default null
* @since 3.0.0
*/
this.currentAnim = null;
/**
* The current AnimationFrame being displayed by this Animation component.
*
* Will by `null` if no animation is yet loaded.
*
* @name Phaser.Animations.AnimationState#currentFrame
* @type {?Phaser.Animations.AnimationFrame}
* @default null
* @since 3.0.0
*/
this.currentFrame = null;
/**
* The key, instance, or config of the next Animation to be loaded into this Animation component
* when the current animation completes.
*
* Will by `null` if no animation has been queued.
*
* @name Phaser.Animations.AnimationState#nextAnim
* @type {?(string|Phaser.Animations.Animation|Phaser.Types.Animations.PlayAnimationConfig)}
* @default null
* @since 3.16.0
*/
this.nextAnim = null;
/**
* A queue of Animations to be loaded into this Animation component when the current animation completes.
*
* Populate this queue via the `chain` method.
*
* @name Phaser.Animations.AnimationState#nextAnimsQueue
* @type {array}
* @since 3.24.0
*/
this.nextAnimsQueue = [];
/**
* The Time Scale factor.
*
* You can adjust this value to modify the passage of time for the animation that is currently
* playing. For example, setting it to 2 will make the animation play twice as fast. Or setting
* it to 0.5 will slow the animation down.
*
* You can change this value at run-time, or set it via the `PlayAnimationConfig`.
*
* Prior to Phaser 3.50 this property was private and called `_timeScale`.
*
* @name Phaser.Animations.AnimationState#timeScale
* @type {number}
* @default 1
* @since 3.50.0
*/
this.timeScale = 1;
/**
* The frame rate of playback, of the current animation, in frames per second.
*
* This value is set when a new animation is loaded into this component and should
* be treated as read-only, as changing it once playback has started will not alter
* the animation. To change the frame rate, provide a new value in the `PlayAnimationConfig` object.
*
* @name Phaser.Animations.AnimationState#frameRate
* @type {number}
* @default 0
* @since 3.0.0
*/
this.frameRate = 0;
/**
* The duration of the current animation, in milliseconds.
*
* This value is set when a new animation is loaded into this component and should
* be treated as read-only, as changing it once playback has started will not alter
* the animation. To change the duration, provide a new value in the `PlayAnimationConfig` object.
*
* @name Phaser.Animations.AnimationState#duration
* @type {number}
* @default 0
* @since 3.0.0
*/
this.duration = 0;
/**
* The number of milliseconds per frame, not including frame specific modifiers that may be present in the
* Animation data.
*
* This value is calculated when a new animation is loaded into this component and should
* be treated as read-only. Changing it will not alter playback speed.
*
* @name Phaser.Animations.AnimationState#msPerFrame
* @type {number}
* @default 0
* @since 3.0.0
*/
this.msPerFrame = 0;
/**
* Skip frames if the time lags, or always advanced anyway?
*
* @name Phaser.Animations.AnimationState#skipMissedFrames
* @type {boolean}
* @default true
* @since 3.0.0
*/
this.skipMissedFrames = true;
/**
* Start playback of this animation from a random frame?
*
* @name Phaser.Animations.AnimationState#randomFrame
* @type {boolean}
* @default false
* @since 3.60.0
*/
this.randomFrame = false;
/**
* The delay before starting playback of the current animation, in milliseconds.
*
* This value is set when a new animation is loaded into this component and should
* be treated as read-only, as changing it once playback has started will not alter
* the animation. To change the delay, provide a new value in the `PlayAnimationConfig` object.
*
* Prior to Phaser 3.50 this property was private and called `_delay`.
*
* @name Phaser.Animations.AnimationState#delay
* @type {number}
* @default 0
* @since 3.50.0
*/
this.delay = 0;
/**
* The number of times to repeat playback of the current animation.
*
* If -1, it means the animation will repeat forever.
*
* This value is set when a new animation is loaded into this component and should
* be treated as read-only, as changing it once playback has started will not alter
* the animation. To change the number of repeats, provide a new value in the `PlayAnimationConfig` object.
*
* Prior to Phaser 3.50 this property was private and called `_repeat`.
*
* @name Phaser.Animations.AnimationState#repeat
* @type {number}
* @default 0
* @since 3.50.0
*/
this.repeat = 0;
/**
* The number of milliseconds to wait before starting the repeat playback of the current animation.
*
* This value is set when a new animation is loaded into this component, but can also be modified
* at run-time.
*
* You can change the repeat delay by providing a new value in the `PlayAnimationConfig` object.
*
* Prior to Phaser 3.50 this property was private and called `_repeatDelay`.
*
* @name Phaser.Animations.AnimationState#repeatDelay
* @type {number}
* @default 0
* @since 3.0.0
*/
this.repeatDelay = 0;
/**
* Should the current animation yoyo? An animation that yoyos will play in reverse, from the end
* to the start, before then repeating or completing. An animation that does not yoyo will just
* play from the start to the end.
*
* This value is set when a new animation is loaded into this component, but can also be modified
* at run-time.
*
* You can change the yoyo by providing a new value in the `PlayAnimationConfig` object.
*
* Prior to Phaser 3.50 this property was private and called `_yoyo`.
*
* @name Phaser.Animations.AnimationState#yoyo
* @type {boolean}
* @default false
* @since 3.50.0
*/
this.yoyo = false;
/**
* If the animation has a delay set, before playback will begin, this
* controls when the first frame is set on the Sprite. If this property
* is 'false' then the frame is set only after the delay has expired.
* This is the default behavior.
*
* If this property is 'true' then the first frame of this animation
* is set immediately, and then when the delay expires, playback starts.
*
* @name Phaser.Animations.AnimationState#showBeforeDelay
* @type {boolean}
* @since 3.60.0
*/
this.showBeforeDelay = false;
/**
* Should the GameObject's `visible` property be set to `true` when the animation starts to play?
*
* This will happen _after_ any delay that may have been set.
*
* This value is set when a new animation is loaded into this component, but can also be modified
* at run-time, assuming the animation is currently delayed.
*
* @name Phaser.Animations.AnimationState#showOnStart
* @type {boolean}
* @since 3.50.0
*/
this.showOnStart = false;
/**
* Should the GameObject's `visible` property be set to `false` when the animation completes?
*
* This value is set when a new animation is loaded into this component, but can also be modified
* at run-time, assuming the animation is still actively playing.
*
* @name Phaser.Animations.AnimationState#hideOnComplete
* @type {boolean}
* @since 3.50.0
*/
this.hideOnComplete = false;
/**
* Is the playhead moving forwards (`true`) or in reverse (`false`) ?
*
* @name Phaser.Animations.AnimationState#forward
* @type {boolean}
* @default true
* @since 3.0.0
*/
this.forward = true;
/**
* An internal trigger that tells the component if it should plays the animation
* in reverse mode ('true') or not ('false'). This is used because `forward` can
* be changed by the `yoyo` feature.
*
* Prior to Phaser 3.50 this property was private and called `_reverse`.
*
* @name Phaser.Animations.AnimationState#inReverse
* @type {boolean}
* @default false
* @since 3.50.0
*/
this.inReverse = false;
/**
* Internal time overflow accumulator.
*
* This has the `delta` time added to it as part of the `update` step.
*
* @name Phaser.Animations.AnimationState#accumulator
* @type {number}
* @default 0
* @since 3.0.0
*/
this.accumulator = 0;
/**
* The time point at which the next animation frame will change.
*
* This value is compared against the `accumulator` as part of the `update` step.
*
* @name Phaser.Animations.AnimationState#nextTick
* @type {number}
* @default 0
* @since 3.0.0
*/
this.nextTick = 0;
/**
* A counter keeping track of how much delay time, in milliseconds, is left before playback begins.
*
* This is set via the `playAfterDelay` method, although it can be modified at run-time
* if required, as long as the animation has not already started playing.
*
* @name Phaser.Animations.AnimationState#delayCounter
* @type {number}
* @default 0
* @since 3.50.0
*/
this.delayCounter = 0;
/**
* A counter that keeps track of how many repeats are left to run.
*
* This value is set when a new animation is loaded into this component, but can also be modified
* at run-time.
*
* @name Phaser.Animations.AnimationState#repeatCounter
* @type {number}
* @default 0
* @since 3.0.0
*/
this.repeatCounter = 0;
/**
* An internal flag keeping track of pending repeats.
*
* @name Phaser.Animations.AnimationState#pendingRepeat
* @type {boolean}
* @default false
* @since 3.0.0
*/
this.pendingRepeat = false;
/**
* Is the Animation paused?
*
* @name Phaser.Animations.AnimationState#_paused
* @type {boolean}
* @private
* @default false
* @since 3.0.0
*/
this._paused = false;
/**
* Was the animation previously playing before being paused?
*
* @name Phaser.Animations.AnimationState#_wasPlaying
* @type {boolean}
* @private
* @default false
* @since 3.0.0
*/
this._wasPlaying = false;
/**
* Internal property tracking if this Animation is waiting to stop.
*
* 0 = No
* 1 = Waiting for ms to pass
* 2 = Waiting for repeat
* 3 = Waiting for specific frame
*
* @name Phaser.Animations.AnimationState#_pendingStop
* @type {number}
* @private
* @since 3.4.0
*/
this._pendingStop = 0;
/**
* Internal property used by _pendingStop.
*
* @name Phaser.Animations.AnimationState#_pendingStopValue
* @type {any}
* @private
* @since 3.4.0
*/
this._pendingStopValue;
},
/**
* Sets an animation, or an array of animations, to be played in the future, after the current one completes or stops.
*
* The current animation must enter a 'completed' state for this to happen, i.e. finish all of its repeats, delays, etc,
* or have one of the `stop` methods called.
*
* An animation set to repeat forever will never enter a completed state unless stopped.
*
* You can chain a new animation at any point, including before the current one starts playing, during it, or when it ends (via its `animationcomplete` event).
*
* Chained animations are specific to a Game Object, meaning different Game Objects can have different chained animations without impacting the global animation they're playing.
*
* Call this method with no arguments to reset all currently chained animations.
*
* @method Phaser.Animations.AnimationState#chain
* @since 3.16.0
*
* @param {(string|Phaser.Animations.Animation|Phaser.Types.Animations.PlayAnimationConfig|string[]|Phaser.Animations.Animation[]|Phaser.Types.Animations.PlayAnimationConfig[])} [key] - The string-based key of the animation to play, or an Animation instance, or a `PlayAnimationConfig` object, or an array of them.
*
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
*/
chain: function (key)
{
var parent = this.parent;
if (key === undefined)
{
this.nextAnimsQueue.length = 0;
this.nextAnim = null;
return parent;
}
if (!Array.isArray(key))
{
key = [ key ];
}
for (var i = 0; i < key.length; i++)
{
var anim = key[i];
if (!this.nextAnim)
{
this.nextAnim = anim;
}
else
{
this.nextAnimsQueue.push(anim);
}
}
return this.parent;
},
/**
* Returns the key of the animation currently loaded into this component.
*
* Prior to Phaser 3.50 this method was called `getCurrentKey`.
*
* @method Phaser.Animations.AnimationState#getName
* @since 3.50.0
*
* @return {string} The key of the Animation currently loaded into this component, or an empty string if none loaded.
*/
getName: function ()
{
return (this.currentAnim) ? this.currentAnim.key : '';
},
/**
* Returns the key of the animation frame currently displayed by this component.
*
* @method Phaser.Animations.AnimationState#getFrameName
* @since 3.50.0
*
* @return {string} The key of the Animation Frame currently displayed by this component, or an empty string if no animation has been loaded.
*/
getFrameName: function ()
{
return (this.currentFrame) ? this.currentFrame.textureFrame : '';
},
/**
* Internal method used to load an animation into this component.
*
* @method Phaser.Animations.AnimationState#load
* @protected
* @since 3.0.0
*
* @param {(string|Phaser.Types.Animations.PlayAnimationConfig)} key - The string-based key of the animation to play, or a `PlayAnimationConfig` object.
*
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
*/
load: function (key)
{
if (this.isPlaying)
{
this.stop();
}
var manager = this.animationManager;
var animKey = (typeof key === 'string') ? key : GetFastValue(key, 'key', null);
// Get the animation, first from the local map and, if not found, from the Animation Manager
var anim = (this.exists(animKey)) ? this.get(animKey) : manager.get(animKey);
if (!anim)
{
console.warn('Missing animation: ' + animKey);
}
else
{
this.currentAnim = anim;
// And now override the animation values, if set in the config.
var totalFrames = anim.getTotalFrames();
var frameRate = GetFastValue(key, 'frameRate', anim.frameRate);
var duration = GetFastValue(key, 'duration', anim.duration);
anim.calculateDuration(this, totalFrames, duration, frameRate);
this.delay = GetFastValue(key, 'delay', anim.delay);
this.repeat = GetFastValue(key, 'repeat', anim.repeat);
this.repeatDelay = GetFastValue(key, 'repeatDelay', anim.repeatDelay);
this.yoyo = GetFastValue(key, 'yoyo', anim.yoyo);
this.showBeforeDelay = GetFastValue(key, 'showBeforeDelay', anim.showBeforeDelay);
this.showOnStart = GetFastValue(key, 'showOnStart', anim.showOnStart);
this.hideOnComplete = GetFastValue(key, 'hideOnComplete', anim.hideOnComplete);
this.skipMissedFrames = GetFastValue(key, 'skipMissedFrames', anim.skipMissedFrames);
this.randomFrame = GetFastValue(key, 'randomFrame', anim.randomFrame);
this.timeScale = GetFastValue(key, 'timeScale', this.timeScale);
var startFrame = GetFastValue(key, 'startFrame', 0);
if (startFrame > totalFrames)
{
startFrame = 0;
}
if (this.randomFrame)
{
startFrame = Between(0, totalFrames - 1);
}
var frame = anim.frames[startFrame];
if (startFrame === 0 && !this.forward)
{
frame = anim.getLastFrame();
}
this.currentFrame = frame;
}
return this.parent;
},
/**
* Pause the current animation and set the `isPlaying` property to `false`.
* You can optionally pause it at a specific frame.
*
* @method Phaser.Animations.AnimationState#pause
* @since 3.0.0
*
* @param {Phaser.Animations.AnimationFrame} [atFrame] - An optional frame to set after pausing the animation.
*
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
*/
pause: function (atFrame)
{
if (!this._paused)
{
this._paused = true;
this._wasPlaying = this.isPlaying;
this.isPlaying = false;
}
if (atFrame !== undefined)
{
this.setCurrentFrame(atFrame);
}
return this.parent;
},
/**
* Resumes playback of a paused animation and sets the `isPlaying` property to `true`.
* You can optionally tell it to start playback from a specific frame.
*
* @method Phaser.Animations.AnimationState#resume
* @since 3.0.0
*
* @param {Phaser.Animations.AnimationFrame} [fromFrame] - An optional frame to set before restarting playback.
*
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
*/
resume: function (fromFrame)
{
if (this._paused)
{
this._paused = false;
this.isPlaying = this._wasPlaying;
}
if (fromFrame !== undefined)
{
this.setCurrentFrame(fromFrame);
}
return this.parent;
},
/**
* Waits for the specified delay, in milliseconds, then starts playback of the given animation.
*
* If the animation _also_ has a delay value set in its config, it will be **added** to the delay given here.
*
* If an animation is already running and a new animation is given to this method, it will wait for
* the given delay before starting the new animation.
*
* If no animation is currently running, the given one begins after the delay.
*
* Prior to Phaser 3.50 this method was called 'delayedPlay' and the parameters were in the reverse order.
*
* @method Phaser.Animations.AnimationState#playAfterDelay
* @fires Phaser.Animations.Events#ANIMATION_START
* @since 3.50.0
*
* @param {(string|Phaser.Animations.Animation|Phaser.Types.Animations.PlayAnimationConfig)} key - The string-based key of the animation to play, or an Animation instance, or a `PlayAnimationConfig` object.
* @param {number} delay - The delay, in milliseconds, to wait before starting the animation playing.
*
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
*/
playAfterDelay: function (key, delay)
{
if (!this.isPlaying)
{
this.delayCounter = delay;
this.play(key, true);
}
else
{
// If we've got a nextAnim, move it to the queue
var nextAnim = this.nextAnim;
var queue = this.nextAnimsQueue;
if (nextAnim)
{
queue.unshift(nextAnim);
}
this.nextAnim = key;
this._pendingStop = 1;
this._pendingStopValue = delay;
}
return this.parent;
},
/**
* Waits for the current animation to complete the `repeatCount` number of repeat cycles, then starts playback
* of the given animation.
*
* You can use this to ensure there are no harsh jumps between two sets of animations, i.e. going from an
* idle animation to a walking animation, by making them blend smoothly into each other.
*
* If no animation is currently running, the given one will start immediately.
*
* @method Phaser.Animations.AnimationState#playAfterRepeat
* @fires Phaser.Animations.Events#ANIMATION_START
* @since 3.50.0
*
* @param {(string|Phaser.Animations.Animation|Phaser.Types.Animations.PlayAnimationConfig)} key - The string-based key of the animation to play, or an Animation instance, or a `PlayAnimationConfig` object.
* @param {number} [repeatCount=1] - How many times should the animation repeat before the next one starts?
*
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
*/
playAfterRepeat: function (key, repeatCount)
{
if (repeatCount === undefined) { repeatCount = 1; }
if (!this.isPlaying)
{
this.play(key);
}
else
{
// If we've got a nextAnim, move it to the queue
var nextAnim = this.nextAnim;
var queue = this.nextAnimsQueue;
if (nextAnim)
{
queue.unshift(nextAnim);
}
if (this.repeatCounter !== -1 && repeatCount > this.repeatCounter)
{
repeatCount = this.repeatCounter;
}
this.nextAnim = key;
this._pendingStop = 2;
this._pendingStopValue = repeatCount;
}
return this.parent;
},
/**
* Start playing the given animation on this Sprite.
*
* Animations in Phaser can either belong to the global Animation Manager, or specifically to this Sprite.
*
* The benefit of a global animation is that multiple Sprites can all play the same animation, without
* having to duplicate the data. You can just create it once and then play it on any Sprite.
*
* The following code shows how to create a global repeating animation. The animation will be created
* from all of the frames within the sprite sheet that was loaded with the key 'muybridge':
*
* ```javascript
* var config = {
* key: 'run',
* frames: 'muybridge',
* frameRate: 15,
* repeat: -1
* };
*
* // This code should be run from within a Scene:
* this.anims.create(config);
* ```
*
* However, if you wish to create an animation that is unique to this Sprite, and this Sprite alone,
* you can call the `Animation.create` method instead. It accepts the exact same parameters as when
* creating a global animation, however the resulting data is kept locally in this Sprite.
*
* With the animation created, either globally or locally, you can now play it on this Sprite:
*
* ```javascript
* this.add.sprite(x, y).play('run');
* ```
*
* Alternatively, if you wish to run it at a different frame rate, for example, you can pass a config
* object instead:
*
* ```javascript
* this.add.sprite(x, y).play({ key: 'run', frameRate: 24 });
* ```
*
* When playing an animation on a Sprite it will first check to see if it can find a matching key
* locally within the Sprite. If it can, it will play the local animation. If not, it will then
* search the global Animation Manager and look for it there.
*
* If you need a Sprite to be able to play both local and global animations, make sure they don't
* have conflicting keys.
*
* See the documentation for the `PlayAnimationConfig` config object for more details about this.
*
* Also, see the documentation in the Animation Manager for further details on creating animations.
*
* @method Phaser.Animations.AnimationState#play
* @fires Phaser.Animations.Events#ANIMATION_START
* @since 3.0.0
*
* @param {(string|Phaser.Animations.Animation|Phaser.Types.Animations.PlayAnimationConfig)} key - The string-based key of the animation to play, or an Animation instance, or a `PlayAnimationConfig` object.
* @param {boolean} [ignoreIfPlaying=false] - If this animation is already playing then ignore this call.
*
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
*/
play: function (key, ignoreIfPlaying)
{
if (ignoreIfPlaying === undefined) { ignoreIfPlaying = false; }
var currentAnim = this.currentAnim;
var parent = this.parent;
// Must be either an Animation instance, or a PlayAnimationConfig object
var animKey = (typeof key === 'string') ? key : key.key;
if (ignoreIfPlaying && this.isPlaying && currentAnim.key === animKey)
{
return parent;
}
// Are we mixing?
if (currentAnim && this.isPlaying)
{
var mix = this.animationManager.getMix(currentAnim.key, key);
if (mix > 0)
{
return this.playAfterDelay(key, mix);
}
}
this.forward = true;
this.inReverse = false;
this._paused = false;
this._wasPlaying = true;
return this.startAnimation(key);
},
/**
* Start playing the given animation on this Sprite, in reverse.
*
* Animations in Phaser can either belong to the global Animation Manager, or specifically to this Sprite.
*
* The benefit of a global animation is that multiple Sprites can all play the same animation, without
* having to duplicate the data. You can just create it once and then play it on any Sprite.
*
* The following code shows how to create a global repeating animation. The animation will be created
* from all of the frames within the sprite sheet that was loaded with the key 'muybridge':
*
* ```javascript
* var config = {
* key: 'run',
* frames: 'muybridge',
* frameRate: 15,
* repeat: -1
* };
*
* // This code should be run from within a Scene:
* this.anims.create(config);
* ```
*
* However, if you wish to create an animation that is unique to this Sprite, and this Sprite alone,
* you can call the `Animation.create` method instead. It accepts the exact same parameters as when
* creating a global animation, however the resulting data is kept locally in this Sprite.
*
* With the animation created, either globally or locally, you can now play it on this Sprite:
*
* ```javascript
* this.add.sprite(x, y).playReverse('run');
* ```
*
* Alternatively, if you wish to run it at a different frame rate, for example, you can pass a config
* object instead:
*
* ```javascript
* this.add.sprite(x, y).playReverse({ key: 'run', frameRate: 24 });
* ```
*
* When playing an animation on a Sprite it will first check to see if it can find a matching key
* locally within the Sprite. If it can, it will play the local animation. If not, it will then
* search the global Animation Manager and look for it there.
*
* If you need a Sprite to be able to play both local and global animations, make sure they don't
* have conflicting keys.
*
* See the documentation for the `PlayAnimationConfig` config object for more details about this.
*
* Also, see the documentation in the Animation Manager for further details on creating animations.
*
* @method Phaser.Animations.AnimationState#playReverse
* @fires Phaser.Animations.Events#ANIMATION_START
* @since 3.12.0
*
* @param {(string|Phaser.Animations.Animation|Phaser.Types.Animations.PlayAnimationConfig)} key - The string-based key of the animation to play, or an Animation instance, or a `PlayAnimationConfig` object.
* @param {boolean} [ignoreIfPlaying=false] - If an animation is already playing then ignore this call.
*
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
*/
playReverse: function (key, ignoreIfPlaying)
{
if (ignoreIfPlaying === undefined) { ignoreIfPlaying = false; }
// Must be either an Animation instance, or a PlayAnimationConfig object
var animKey = (typeof key === 'string') ? key : key.key;
if (ignoreIfPlaying && this.isPlaying && this.currentAnim.key === animKey)
{
return this.parent;
}
this.forward = false;
this.inReverse = true;
this._paused = false;
this._wasPlaying = true;
return this.startAnimation(key);
},
/**
* Load the animation based on the key and set-up all of the internal values
* needed for playback to start. If there is no delay, it will also fire the start events.
*
* @method Phaser.Animations.AnimationState#startAnimation
* @fires Phaser.Animations.Events#ANIMATION_START
* @since 3.50.0
*
* @param {(string|Phaser.Types.Animations.PlayAnimationConfig)} key - The string-based key of the animation to play, or a `PlayAnimationConfig` object.
*
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
*/
startAnimation: function (key)
{
this.load(key);
var anim = this.currentAnim;
var gameObject = this.parent;
if (!anim)
{
return gameObject;
}
// Should give us 9,007,199,254,740,991 safe repeats
this.repeatCounter = (this.repeat === -1) ? Number.MAX_VALUE : this.repeat;