0
# Animation Systems
1
2
Phaser provides two powerful animation systems: frame-based animations for sprite sequences and tween animations for smooth property interpolation. These systems work together to create rich, dynamic visual effects.
3
4
## Frame-Based Animations
5
6
### Animation Manager
7
The global animation manager handles all sprite animations:
8
9
```javascript { .api }
10
class AnimationScene extends Phaser.Scene {
11
preload() {
12
// Load spritesheet for animations
13
this.load.spritesheet('player', 'assets/player.png', {
14
frameWidth: 32,
15
frameHeight: 48
16
});
17
18
// Load texture atlas
19
this.load.atlas('characters', 'assets/characters.png', 'assets/characters.json');
20
}
21
22
create() {
23
// Create animations from spritesheet
24
this.anims.create({
25
key: 'player-walk',
26
frames: this.anims.generateFrameNumbers('player', { start: 0, end: 3 }),
27
frameRate: 10,
28
repeat: -1
29
});
30
31
this.anims.create({
32
key: 'player-idle',
33
frames: [{ key: 'player', frame: 4 }],
34
frameRate: 20
35
});
36
37
// Create animations from texture atlas
38
this.anims.create({
39
key: 'enemy-attack',
40
frames: this.anims.generateFrameNames('characters', {
41
prefix: 'enemy-attack-',
42
start: 1,
43
end: 6,
44
zeroPad: 3
45
}),
46
frameRate: 15,
47
repeat: 0
48
});
49
50
// Complex animation configuration
51
this.anims.create({
52
key: 'explosion',
53
frames: this.anims.generateFrameNumbers('explosion', { start: 0, end: 15 }),
54
frameRate: 20,
55
repeat: 0,
56
hideOnComplete: true,
57
yoyo: false,
58
delay: 0,
59
repeatDelay: 0,
60
showOnStart: true,
61
randomFrame: false,
62
duration: 800 // Override frameRate calculation
63
});
64
}
65
}
66
```
67
68
### Animation Configuration
69
Comprehensive animation options:
70
71
```javascript { .api }
72
// Animation creation with all options
73
scene.anims.create({
74
key: 'complex-animation',
75
frames: scene.anims.generateFrameNumbers('sprite', { start: 0, end: 7 }),
76
77
// Timing
78
frameRate: 12, // Frames per second
79
duration: 1000, // Total duration (overrides frameRate)
80
delay: 500, // Delay before starting
81
82
// Repetition
83
repeat: 3, // Number of repeats (-1 = infinite)
84
repeatDelay: 200, // Delay between repeats
85
yoyo: true, // Play forward then backward
86
87
// Visibility
88
showOnStart: true, // Show sprite when animation starts
89
hideOnComplete: false, // Hide sprite when animation completes
90
91
// Frame selection
92
randomFrame: false, // Start on random frame
93
skipMissedFrames: true, // Skip frames if running slow
94
95
// Events
96
onStart: (animation, frame, gameObject) => {
97
console.log('Animation started');
98
},
99
onRepeat: (animation, frame, gameObject) => {
100
console.log('Animation repeated');
101
},
102
onUpdate: (animation, frame, gameObject) => {
103
console.log('Frame updated to:', frame.index);
104
},
105
onComplete: (animation, frame, gameObject) => {
106
console.log('Animation completed');
107
}
108
});
109
```
110
111
### Frame Generation
112
Multiple ways to generate frame sequences:
113
114
```javascript { .api }
115
class FrameGenerationScene extends Phaser.Scene {
116
create() {
117
// Generate numbered frames
118
const walkFrames = this.anims.generateFrameNumbers('player', {
119
start: 0,
120
end: 7,
121
first: 1 // First frame to use (optional)
122
});
123
124
// Generate named frames (for texture atlas)
125
const runFrames = this.anims.generateFrameNames('atlas', {
126
prefix: 'run-',
127
suffix: '.png',
128
start: 1,
129
end: 8,
130
zeroPad: 3 // Pad numbers to 3 digits (001, 002, etc.)
131
});
132
133
// Custom frame array
134
const customFrames = [
135
{ key: 'atlas', frame: 'idle-1' },
136
{ key: 'atlas', frame: 'idle-2', duration: 100 }, // Custom frame duration
137
{ key: 'atlas', frame: 'idle-3' },
138
{ key: 'player', frame: 0 } // Mix different textures
139
];
140
141
// Create animations
142
this.anims.create({
143
key: 'walk',
144
frames: walkFrames,
145
frameRate: 10,
146
repeat: -1
147
});
148
149
this.anims.create({
150
key: 'run',
151
frames: runFrames,
152
frameRate: 15,
153
repeat: -1
154
});
155
156
this.anims.create({
157
key: 'custom',
158
frames: customFrames,
159
frameRate: 8,
160
repeat: -1
161
});
162
}
163
}
164
```
165
166
### Animation Control
167
Control animations on GameObjects:
168
169
```javascript { .api }
170
class AnimationControlScene extends Phaser.Scene {
171
create() {
172
this.player = this.add.sprite(400, 300, 'player');
173
174
// Play animation
175
this.player.play('walk');
176
177
// Play with options
178
this.player.play({
179
key: 'walk',
180
ignoreIfPlaying: false, // Restart even if already playing
181
startFrame: 2, // Start from specific frame
182
timeScale: 1.5 // Play 1.5x speed
183
});
184
185
// Animation state queries
186
console.log('Is playing:', this.player.anims.isPlaying);
187
console.log('Current animation:', this.player.anims.currentAnim);
188
console.log('Current frame:', this.player.anims.currentFrame);
189
console.log('Total frames:', this.player.anims.getTotalFrames());
190
console.log('Progress:', this.player.anims.getProgress());
191
192
// Animation control
193
this.player.anims.pause();
194
this.player.anims.resume();
195
this.player.anims.stop();
196
this.player.anims.restart();
197
198
// Play in reverse
199
this.player.playReverse('walk');
200
201
// Chain animations
202
this.player.chain(['walk', 'idle', 'jump']);
203
204
// Set time scale (speed multiplier)
205
this.player.anims.setTimeScale(2.0);
206
207
// Seek to specific progress
208
this.player.anims.setProgress(0.5); // 50% through animation
209
210
// Set repeat count
211
this.player.anims.setRepeat(5);
212
213
// Manual frame control
214
this.player.setFrame(3);
215
this.player.anims.nextFrame();
216
this.player.anims.previousFrame();
217
}
218
}
219
```
220
221
### Animation Events
222
Listen for animation events:
223
224
```javascript { .api }
225
class AnimationEventsScene extends Phaser.Scene {
226
create() {
227
this.player = this.add.sprite(400, 300, 'player');
228
229
// Global animation events (all sprites)
230
this.anims.on('animationstart', (anim, frame, gameObject) => {
231
console.log('Any animation started:', anim.key);
232
});
233
234
this.anims.on('animationcomplete', (anim, frame, gameObject) => {
235
console.log('Any animation completed:', anim.key);
236
});
237
238
// Specific animation events
239
this.anims.on('animationcomplete-walk', (anim, frame, gameObject) => {
240
console.log('Walk animation completed');
241
gameObject.play('idle');
242
});
243
244
// Sprite-specific events
245
this.player.on('animationstart', (anim, frame) => {
246
console.log('Player animation started:', anim.key);
247
});
248
249
this.player.on('animationupdate', (anim, frame) => {
250
console.log('Player frame:', frame.index);
251
252
// Trigger effects on specific frames
253
if (frame.index === 2) {
254
this.createFootstepEffect();
255
}
256
});
257
258
this.player.on('animationrepeat', (anim, frame) => {
259
console.log('Player animation repeated');
260
});
261
262
this.player.on('animationcomplete', (anim, frame) => {
263
console.log('Player animation completed');
264
265
// Handle animation completion
266
if (anim.key === 'attack') {
267
this.player.play('idle');
268
} else if (anim.key === 'death') {
269
this.gameOver();
270
}
271
});
272
}
273
}
274
```
275
276
## Tween Animations
277
278
### Basic Tweens
279
Smooth property interpolation:
280
281
```javascript { .api }
282
class TweenBasicsScene extends Phaser.Scene {
283
create() {
284
this.sprite = this.add.sprite(100, 300, 'player');
285
286
// Basic tween
287
this.tweens.add({
288
targets: this.sprite,
289
x: 700,
290
duration: 2000,
291
ease: 'Power2'
292
});
293
294
// Multiple properties
295
this.tweens.add({
296
targets: this.sprite,
297
x: 400,
298
y: 100,
299
scaleX: 2,
300
scaleY: 2,
301
rotation: Math.PI,
302
alpha: 0.5,
303
duration: 1500,
304
ease: 'Bounce.easeOut'
305
});
306
307
// Relative values
308
this.tweens.add({
309
targets: this.sprite,
310
x: '+=100', // Relative to current value
311
y: '-=50',
312
rotation: '+=0.5',
313
duration: 1000
314
});
315
316
// Array of values (tween through each)
317
this.tweens.add({
318
targets: this.sprite,
319
x: [100, 300, 500, 700],
320
y: [100, 200, 300, 100],
321
duration: 3000,
322
ease: 'Linear'
323
});
324
}
325
}
326
```
327
328
### Tween Configuration
329
Comprehensive tween options:
330
331
```javascript { .api }
332
class TweenConfigScene extends Phaser.Scene {
333
create() {
334
const sprite = this.add.sprite(400, 300, 'player');
335
336
// Full configuration
337
this.tweens.add({
338
targets: sprite,
339
340
// Properties to tween
341
x: 600,
342
y: 200,
343
scaleX: 1.5,
344
alpha: 0.8,
345
346
// Timing
347
duration: 2000,
348
delay: 500, // Delay before starting
349
350
// Repetition
351
repeat: 2, // Number of repeats (-1 = infinite)
352
repeatDelay: 300, // Delay between repeats
353
yoyo: true, // Return to start values
354
355
// Easing
356
ease: 'Power2.easeInOut',
357
358
// Hold
359
hold: 1000, // Hold at end values
360
361
// Callbacks
362
onStart: (tween, targets) => {
363
console.log('Tween started');
364
},
365
onUpdate: (tween, target) => {
366
console.log('Tween progress:', tween.progress);
367
},
368
onRepeat: (tween, target) => {
369
console.log('Tween repeated');
370
},
371
onComplete: (tween, targets) => {
372
console.log('Tween completed');
373
},
374
375
// Callback scope and parameters
376
callbackScope: this,
377
onCompleteParams: ['param1', 'param2']
378
});
379
}
380
}
381
```
382
383
### Easing Functions
384
Rich collection of easing functions:
385
386
```javascript { .api }
387
// Linear
388
'Linear'
389
390
// Quadratic
391
'Quad.easeIn'
392
'Quad.easeOut'
393
'Quad.easeInOut'
394
'Power1' // Same as Quad
395
396
// Cubic
397
'Cubic.easeIn'
398
'Cubic.easeOut'
399
'Cubic.easeInOut'
400
'Power2' // Same as Cubic
401
402
// Quartic
403
'Quart.easeIn'
404
'Quart.easeOut'
405
'Quart.easeInOut'
406
'Power3' // Same as Quart
407
408
// Quintic
409
'Quint.easeIn'
410
'Quint.easeOut'
411
'Quint.easeInOut'
412
'Power4' // Same as Quint
413
414
// Sine
415
'Sine.easeIn'
416
'Sine.easeOut'
417
'Sine.easeInOut'
418
419
// Exponential
420
'Expo.easeIn'
421
'Expo.easeOut'
422
'Expo.easeInOut'
423
424
// Circular
425
'Circ.easeIn'
426
'Circ.easeOut'
427
'Circ.easeInOut'
428
429
// Back
430
'Back.easeIn'
431
'Back.easeOut'
432
'Back.easeInOut'
433
434
// Elastic
435
'Elastic.easeIn'
436
'Elastic.easeOut'
437
'Elastic.easeInOut'
438
439
// Bounce
440
'Bounce.easeIn'
441
'Bounce.easeOut'
442
'Bounce.easeInOut'
443
444
// Stepped
445
'Stepped'
446
447
// Custom easing function
448
function customEase(t) {
449
return t * t * (3 - 2 * t); // Smoothstep
450
}
451
```
452
453
### Tween Control
454
Control tween playback:
455
456
```javascript { .api }
457
class TweenControlScene extends Phaser.Scene {
458
create() {
459
this.sprite = this.add.sprite(100, 300, 'player');
460
461
// Store tween reference
462
this.myTween = this.tweens.add({
463
targets: this.sprite,
464
x: 700,
465
duration: 3000,
466
paused: true // Start paused
467
});
468
469
// Tween control methods
470
this.myTween.play(); // Start/resume
471
this.myTween.pause(); // Pause
472
this.myTween.resume(); // Resume
473
this.myTween.stop(); // Stop
474
this.myTween.restart(); // Restart from beginning
475
476
// Seek to specific progress
477
this.myTween.seek(0.5); // Jump to 50% completion
478
479
// Update target values while running
480
this.myTween.updateTo('x', 500); // Change target to 500
481
this.myTween.updateTo('y', 200, true); // Change target, start from current
482
483
// Time scale (speed multiplier)
484
this.myTween.setTimeScale(2); // 2x speed
485
486
// Tween properties
487
console.log('Progress:', this.myTween.progress);
488
console.log('Duration:', this.myTween.duration);
489
console.log('Is playing:', this.myTween.isPlaying());
490
console.log('Is paused:', this.myTween.isPaused());
491
console.log('Has started:', this.myTween.hasStarted);
492
}
493
}
494
```
495
496
### Multiple Target Tweens
497
Tween multiple objects simultaneously:
498
499
```javascript { .api }
500
class MultiTargetScene extends Phaser.Scene {
501
create() {
502
// Create multiple sprites
503
const sprites = [];
504
for (let i = 0; i < 5; i++) {
505
sprites.push(this.add.sprite(100 + i * 100, 300, 'player'));
506
}
507
508
// Tween all sprites together
509
this.tweens.add({
510
targets: sprites,
511
y: 100,
512
duration: 1000,
513
ease: 'Bounce.easeOut'
514
});
515
516
// Staggered animation
517
this.tweens.add({
518
targets: sprites,
519
x: 600,
520
duration: 500,
521
delay: this.tweens.stagger(100) // 100ms delay between each
522
});
523
524
// Staggered with options
525
this.tweens.add({
526
targets: sprites,
527
scaleX: 2,
528
scaleY: 2,
529
duration: 800,
530
delay: this.tweens.stagger(150, { start: 500, from: 'center' })
531
});
532
}
533
}
534
```
535
536
### Tween Chains and Timelines
537
Sequence multiple animations:
538
539
```javascript { .api }
540
class TweenChainScene extends Phaser.Scene {
541
create() {
542
this.sprite = this.add.sprite(100, 300, 'player');
543
544
// Chain tweens together
545
const tween1 = this.tweens.add({
546
targets: this.sprite,
547
x: 400,
548
duration: 1000,
549
paused: true
550
});
551
552
const tween2 = this.tweens.add({
553
targets: this.sprite,
554
y: 100,
555
duration: 1000,
556
paused: true
557
});
558
559
const tween3 = this.tweens.add({
560
targets: this.sprite,
561
rotation: Math.PI * 2,
562
duration: 1000,
563
paused: true
564
});
565
566
// Create chain
567
this.tweens.chain({
568
tweens: [tween1, tween2, tween3]
569
}).play();
570
571
// Timeline for complex sequences
572
const timeline = this.tweens.timeline({
573
targets: this.sprite,
574
575
// Timeline tweens
576
tweens: [
577
{
578
x: 300,
579
duration: 1000
580
},
581
{
582
y: 200,
583
duration: 500,
584
offset: 800 // Start 800ms into timeline
585
},
586
{
587
rotation: Math.PI,
588
duration: 1000,
589
offset: '-=500' // Start 500ms before previous ends
590
}
591
],
592
593
// Timeline options
594
loop: 2,
595
loopDelay: 1000,
596
onComplete: () => {
597
console.log('Timeline complete');
598
}
599
});
600
}
601
}
602
```
603
604
### Counter Tweens
605
Animate numbers and custom values:
606
607
```javascript { .api }
608
class CounterTweenScene extends Phaser.Scene {
609
create() {
610
// Score counter
611
this.score = 0;
612
this.scoreText = this.add.text(400, 100, 'Score: 0', {
613
fontSize: '32px',
614
fill: '#ffffff'
615
});
616
617
// Tween the score value
618
this.tweens.addCounter({
619
from: 0,
620
to: 1000,
621
duration: 2000,
622
onUpdate: (tween) => {
623
this.score = Math.floor(tween.getValue());
624
this.scoreText.setText('Score: ' + this.score);
625
}
626
});
627
628
// Health bar animation
629
this.healthBarWidth = 200;
630
this.healthBar = this.add.rectangle(400, 200, this.healthBarWidth, 20, 0x00ff00);
631
632
this.tweens.addCounter({
633
from: 100,
634
to: 25,
635
duration: 3000,
636
ease: 'Power2.easeIn',
637
onUpdate: (tween) => {
638
const health = tween.getValue();
639
this.healthBar.width = (health / 100) * this.healthBarWidth;
640
641
// Change color based on health
642
if (health > 60) {
643
this.healthBar.fillColor = 0x00ff00; // Green
644
} else if (health > 30) {
645
this.healthBar.fillColor = 0xffff00; // Yellow
646
} else {
647
this.healthBar.fillColor = 0xff0000; // Red
648
}
649
}
650
});
651
}
652
}
653
```
654
655
### Tween Manager
656
Access and control all tweens:
657
658
```javascript { .api }
659
class TweenManagerScene extends Phaser.Scene {
660
create() {
661
// Create some tweens
662
const sprites = [
663
this.add.sprite(100, 100, 'player'),
664
this.add.sprite(200, 200, 'player'),
665
this.add.sprite(300, 300, 'player')
666
];
667
668
sprites.forEach(sprite => {
669
this.tweens.add({
670
targets: sprite,
671
x: 600,
672
duration: 2000,
673
repeat: -1,
674
yoyo: true
675
});
676
});
677
678
// Manager operations
679
const allTweens = this.tweens.getAllTweens();
680
console.log('Total tweens:', allTweens.length);
681
682
// Get tweens of specific object
683
const spriteTweens = this.tweens.getTweensOf(sprites[0]);
684
685
// Check if object is being tweened
686
const isTweening = this.tweens.isTweening(sprites[0]);
687
688
// Kill all tweens of object
689
this.tweens.killTweensOf(sprites[1]);
690
691
// Global tween control
692
this.tweens.pauseAll();
693
this.tweens.resumeAll();
694
this.tweens.killAll();
695
696
// Global time scale
697
this.tweens.setGlobalTimeScale(0.5); // Half speed
698
console.log('Global time scale:', this.tweens.getGlobalTimeScale());
699
}
700
}
701
```
702
703
## Advanced Animation Techniques
704
705
### Physics-Based Animations
706
Combine tweens with physics:
707
708
```javascript { .api }
709
class PhysicsAnimationScene extends Phaser.Scene {
710
create() {
711
// Enable physics
712
this.physics.world.gravity.y = 300;
713
714
this.ball = this.physics.add.sprite(100, 100, 'ball');
715
this.ball.setBounce(0.8);
716
this.ball.setCollideWorldBounds(true);
717
718
// Animate physics properties
719
this.tweens.add({
720
targets: this.ball.body.velocity,
721
x: 200,
722
y: -400,
723
duration: 500
724
});
725
726
// Animate gravity
727
this.tweens.add({
728
targets: this.physics.world.gravity,
729
y: 800,
730
duration: 3000,
731
yoyo: true,
732
repeat: -1
733
});
734
}
735
}
736
```
737
738
### Particle Animation
739
Animate particle system properties:
740
741
```javascript { .api }
742
class ParticleAnimationScene extends Phaser.Scene {
743
create() {
744
// Create particle emitter
745
this.particles = this.add.particles(400, 300, 'particle', {
746
speed: { min: 100, max: 200 },
747
lifespan: 1000,
748
quantity: 5
749
});
750
751
// Animate emitter properties
752
this.tweens.add({
753
targets: this.particles,
754
x: 600,
755
y: 200,
756
duration: 2000,
757
yoyo: true,
758
repeat: -1
759
});
760
761
// Animate emission rate
762
this.tweens.addCounter({
763
from: 5,
764
to: 50,
765
duration: 3000,
766
yoyo: true,
767
repeat: -1,
768
onUpdate: (tween) => {
769
this.particles.setQuantity(tween.getValue());
770
}
771
});
772
}
773
}
774
```
775
776
### Morphing Animations
777
Animate shape transformations:
778
779
```javascript { .api }
780
class MorphingScene extends Phaser.Scene {
781
create() {
782
this.graphics = this.add.graphics();
783
784
// Start shape
785
this.currentShape = {
786
x: 200,
787
y: 200,
788
radius: 50,
789
sides: 3
790
};
791
792
this.drawShape();
793
794
// Morph to different shape
795
this.tweens.add({
796
targets: this.currentShape,
797
radius: 100,
798
sides: 8,
799
duration: 2000,
800
ease: 'Power2.easeInOut',
801
onUpdate: () => {
802
this.drawShape();
803
}
804
});
805
}
806
807
drawShape() {
808
this.graphics.clear();
809
this.graphics.fillStyle(0x00ff00);
810
811
const sides = Math.round(this.currentShape.sides);
812
const angleStep = (Math.PI * 2) / sides;
813
814
this.graphics.beginPath();
815
for (let i = 0; i <= sides; i++) {
816
const angle = i * angleStep;
817
const x = this.currentShape.x + Math.cos(angle) * this.currentShape.radius;
818
const y = this.currentShape.y + Math.sin(angle) * this.currentShape.radius;
819
820
if (i === 0) {
821
this.graphics.moveTo(x, y);
822
} else {
823
this.graphics.lineTo(x, y);
824
}
825
}
826
this.graphics.fillPath();
827
}
828
}
829
```
830
831
This comprehensive animation system provides all the tools needed to create engaging, smooth animations that bring games to life with both sprite sequences and property tweening.