Skip to content

Commit 89332aa

Browse files
committed
You can now create Animations directly on Sprite
* `Component.Animation.create` is a new method that allows you to create animations directly on a Sprite. These are not global and never enter the Animation Manager, instead risiding within the Sprite itself. This allows you to use the same keys across both local and global animations and set-up Sprite specific local animations. * All playback methods: `play`, `playReverse`, `playAfterDelay` and `playAfterRepeat` will now check to see if the given animation key exists locally on the Sprite first. If it does, it's used, otherwise it then checks the global Animation Manager for the key instead. * `Component.Animation.remove` is a new method that will remove a locally stored Animation instance from a Sprite. * `Component.Animation.get` is a new method that will return a locally stored Animation instance from the Sprite. * `Component.Animation.exists` is a new method that will check if a locally stored Animation exists on the Sprite. * The internal `Component.Animation.remove` method has been renamed to `globalRemove`. * `Component.Animation.textureManager` is a new property that references the global Texture Manager. * `Component.Animation.anims` is a new property that contains locally created Animations in a Custom Map.
1 parent cee9ca0 commit 89332aa

1 file changed

Lines changed: 250 additions & 15 deletions

File tree

src/gameobjects/components/Animation.js

Lines changed: 250 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
*/
66

77
var Class = require('../../utils/Class');
8+
var CustomMap = require('../../structs/Map');
89
var GetFastValue = require('../../utils/object/GetFastValue');
910
var Events = require('../../animations/events');
11+
var AnimationClass = require('../../animations/Animation');
1012

1113
/**
1214
* @classdesc
@@ -52,7 +54,30 @@ var Animation = new Class({
5254
*/
5355
this.animationManager = parent.scene.sys.anims;
5456

55-
this.animationManager.on(Events.REMOVE_ANIMATION, this.remove, this);
57+
this.animationManager.on(Events.REMOVE_ANIMATION, this.globalRemove, this);
58+
59+
/**
60+
* A reference to the Texture Manager.
61+
*
62+
* @name Phaser.GameObjects.Components.Animation#textureManager
63+
* @type {Phaser.Textures.TextureManager}
64+
* @protected
65+
* @since 3.50.0
66+
*/
67+
this.textureManager = this.animationManager.textureManager;
68+
69+
/**
70+
* The Animations stored locally in this Animation component.
71+
*
72+
* Do not modify the contents of this Map directly, instead use the
73+
* `add`, `create` and `remove` methods of this class instead.
74+
*
75+
* @name Phaser.GameObjects.Components.Animation#anims
76+
* @type {Phaser.Structs.Map.<string, Phaser.Animations.Animation>}
77+
* @protected
78+
* @since 3.50.0
79+
*/
80+
this.anims = null;
5681

5782
/**
5883
* Is an animation currently playing or not?
@@ -262,7 +287,6 @@ var Animation = new Class({
262287
*/
263288
this.yoyo = false;
264289

265-
266290
/**
267291
* Should the GameObject's `visible` property be set to `true` when the animation starts to play?
268292
*
@@ -512,8 +536,8 @@ var Animation = new Class({
512536
var manager = this.animationManager;
513537
var animKey = (typeof key === 'string') ? key : GetFastValue(key, 'key', null);
514538

515-
// Get the animation from the Animation Manager
516-
var anim = manager.get(animKey);
539+
// Get the animation, first from the local map and, if not found, from the Animation Manager
540+
var anim = (this.exists(animKey)) ? this.get(animKey) : manager.get(animKey);
517541

518542
if (!anim)
519543
{
@@ -552,7 +576,7 @@ var Animation = new Class({
552576

553577
if (startFrame === 0 && !this.forward)
554578
{
555-
frame = this.getLastFrame();
579+
frame = anim.getLastFrame();
556580
}
557581

558582
this.currentFrame = frame;
@@ -668,10 +692,11 @@ var Animation = new Class({
668692
},
669693

670694
/**
671-
* Waits for the current animation to complete one 'repeat' cycle, then starts playback of the given animation.
695+
* Waits for the current animation to complete the `repeatCount` number of repeat cycles, then starts playback
696+
* of the given animation.
672697
*
673-
* You can use this to ensure there are no harsh 'jumps' between two sets of animations, i.e. going from an
674-
* idle animation to a walking animation.
698+
* You can use this to ensure there are no harsh jumps between two sets of animations, i.e. going from an
699+
* idle animation to a walking animation, by making them blend smoothly into each other.
675700
*
676701
* If no animation is currently running, the given one will start immediately.
677702
*
@@ -720,9 +745,55 @@ var Animation = new Class({
720745
},
721746

722747
/**
723-
* Plays an Animation on a Game Object that has the Animation component, such as a Sprite.
748+
* Start playing the given animation on this Sprite.
749+
*
750+
* Animations in Phaser can either belong to the global Animation Manager, or specifically to this Sprite.
751+
*
752+
* The benefit of a global animation is that multiple Sprites can all play the same animation, without
753+
* having to duplicate the data. You can just create it once and then play it on any Sprite.
724754
*
725-
* Animations are stored in the global Animation Manager and are referenced by a unique string-based key.
755+
* The following code shows how to create a global repeating animation. The animation will be created
756+
* from all of the frames within the sprite sheet that was loaded with the key 'muybridge':
757+
*
758+
* ```javascript
759+
* var config = {
760+
* key: 'run',
761+
* frames: 'muybridge',
762+
* frameRate: 15,
763+
* repeat: -1
764+
* };
765+
*
766+
* // This code should be run from within a Scene:
767+
* this.anims.create(config);
768+
* ```
769+
*
770+
* However, if you wish to create an animation that is unique to this Sprite, and this Sprite alone,
771+
* you can call the `Animation.create` method instead. It accepts the exact same parameters as when
772+
* creating a global animation, however the resulting data is kept locally in this Sprite.
773+
*
774+
* With the animation created, either globally or locally, you can now play it on this Sprite:
775+
*
776+
* ```javascript
777+
* this.add.sprite(x, y).play('run');
778+
* ```
779+
*
780+
* Alternatively, if you wish to run it at a different frame rate, for example, you can pass a config
781+
* object instead:
782+
*
783+
* ```javascript
784+
* this.add.sprite(x, y).play({ key: 'run', frameRate: 24 });
785+
* ```
786+
*
787+
* When playing an animation on a Sprite it will first check to see if it can find a matching key
788+
* locally within the Sprite. If it can, it will play the local animation. If not, it will then
789+
* search the global Animation Manager and look for it there.
790+
*
791+
* If you need a Sprite to be able to play both local and global animations, make sure they don't
792+
* have conflicting keys.
793+
*
794+
* See the documentation for the `PlayAnimationConfig` config object for more details about this.
795+
*
796+
* Also, see the documentation in the Animation Manager for further details on creating animations.
726797
*
727798
* @method Phaser.GameObjects.Components.Animation#play
728799
* @fires Phaser.Animations.Events#ANIMATION_START
@@ -757,7 +828,55 @@ var Animation = new Class({
757828
},
758829

759830
/**
760-
* Plays an Animation in reverse on the Game Object that owns this Animation Component.
831+
* Start playing the given animation on this Sprite, in reverse.
832+
*
833+
* Animations in Phaser can either belong to the global Animation Manager, or specifically to this Sprite.
834+
*
835+
* The benefit of a global animation is that multiple Sprites can all play the same animation, without
836+
* having to duplicate the data. You can just create it once and then play it on any Sprite.
837+
*
838+
* The following code shows how to create a global repeating animation. The animation will be created
839+
* from all of the frames within the sprite sheet that was loaded with the key 'muybridge':
840+
*
841+
* ```javascript
842+
* var config = {
843+
* key: 'run',
844+
* frames: 'muybridge',
845+
* frameRate: 15,
846+
* repeat: -1
847+
* };
848+
*
849+
* // This code should be run from within a Scene:
850+
* this.anims.create(config);
851+
* ```
852+
*
853+
* However, if you wish to create an animation that is unique to this Sprite, and this Sprite alone,
854+
* you can call the `Animation.create` method instead. It accepts the exact same parameters as when
855+
* creating a global animation, however the resulting data is kept locally in this Sprite.
856+
*
857+
* With the animation created, either globally or locally, you can now play it on this Sprite:
858+
*
859+
* ```javascript
860+
* this.add.sprite(x, y).playReverse('run');
861+
* ```
862+
*
863+
* Alternatively, if you wish to run it at a different frame rate, for example, you can pass a config
864+
* object instead:
865+
*
866+
* ```javascript
867+
* this.add.sprite(x, y).playReverse({ key: 'run', frameRate: 24 });
868+
* ```
869+
*
870+
* When playing an animation on a Sprite it will first check to see if it can find a matching key
871+
* locally within the Sprite. If it can, it will play the local animation. If not, it will then
872+
* search the global Animation Manager and look for it there.
873+
*
874+
* If you need a Sprite to be able to play both local and global animations, make sure they don't
875+
* have conflicting keys.
876+
*
877+
* See the documentation for the `PlayAnimationConfig` config object for more details about this.
878+
*
879+
* Also, see the documentation in the Animation Manager for further details on creating animations.
761880
*
762881
* @method Phaser.GameObjects.Components.Animation#playReverse
763882
* @fires Phaser.Animations.Events#ANIMATION_START
@@ -1041,13 +1160,13 @@ var Animation = new Class({
10411160
/**
10421161
* Handle the removal of an animation from the Animation Manager.
10431162
*
1044-
* @method Phaser.GameObjects.Components.Animation#remove
1045-
* @since 3.0.0
1163+
* @method Phaser.GameObjects.Components.Animation#globalRemove
1164+
* @since 3.50.0
10461165
*
10471166
* @param {string} [key] - The key of the removed Animation.
10481167
* @param {Phaser.Animations.Animation} [animation] - The removed Animation.
10491168
*/
1050-
remove: function (key, animation)
1169+
globalRemove: function (key, animation)
10511170
{
10521171
if (animation === undefined) { animation = this.currentAnim; }
10531172

@@ -1479,6 +1598,117 @@ var Animation = new Class({
14791598
return this.parent;
14801599
},
14811600

1601+
/**
1602+
* Get an Animation instance that has been created locally on this Sprite.
1603+
*
1604+
* See the `create` method for more details.
1605+
*
1606+
* @method Phaser.GameObjects.Components.Animation#get
1607+
* @since 3.50.0
1608+
*
1609+
* @param {string} key - The key of the Animation to retrieve.
1610+
*
1611+
* @return {Phaser.Animations.Animation} The Animation, or `undefined` if the key is invalid.
1612+
*/
1613+
get: function (key)
1614+
{
1615+
return (this.anims && this.anims.get(key));
1616+
},
1617+
1618+
/**
1619+
* Checks to see if the given key is already used locally within the animations stored on this Sprite.
1620+
*
1621+
* @method Phaser.GameObjects.Components.Animation#exists
1622+
* @since 3.50.0
1623+
*
1624+
* @param {string} key - The key of the Animation to check.
1625+
*
1626+
* @return {boolean} `true` if the Animation exists locally, or `false` if the key is available.
1627+
*/
1628+
exists: function (key)
1629+
{
1630+
return (this.anims && this.anims.has(key));
1631+
},
1632+
1633+
/**
1634+
* Creates a new Animation that is local specifically to this Sprite.
1635+
*
1636+
* When a Sprite owns an animation, it is kept out of the global Animation Manager, which means
1637+
* you're free to use keys that may be already defined there. Unless you specifically need a Sprite
1638+
* to have a unique animation, you should favor using global animations instead, as they allow for
1639+
* the same animation to be used across multiple Sprites, saving on memory. However, if this Sprite
1640+
* is the only one to use this animation, it's sensible to create it here.
1641+
*
1642+
* If an invalid key is given this method will return `false`.
1643+
*
1644+
* If you pass the key of an animation that already exists locally, that animation will be returned.
1645+
*
1646+
* A brand new animation is only created if the key is valid and not already in use by this Sprite.
1647+
*
1648+
* If you wish to re-use an existing key, call the `remove` method first, then this method.
1649+
*
1650+
* @method Phaser.GameObjects.Components.Animation#create
1651+
* @since 3.50.0
1652+
*
1653+
* @param {Phaser.Types.Animations.Animation} config - The configuration settings for the Animation.
1654+
*
1655+
* @return {(Phaser.Animations.Animation|false)} The Animation that was created, or `false` if the key is already in use.
1656+
*/
1657+
create: function (config)
1658+
{
1659+
var key = config.key;
1660+
1661+
var anim = false;
1662+
1663+
if (key)
1664+
{
1665+
anim = this.get(key);
1666+
1667+
if (!anim)
1668+
{
1669+
anim = new AnimationClass(this, key, config);
1670+
1671+
if (!this.anims)
1672+
{
1673+
this.anims = new CustomMap();
1674+
}
1675+
1676+
this.anims.set(key, anim);
1677+
}
1678+
}
1679+
1680+
return anim;
1681+
},
1682+
1683+
/**
1684+
* Removes a locally created Animation from this Sprite, based on the given key.
1685+
*
1686+
* Once an Animation has been removed, this Sprite cannot play it again without re-creating it.
1687+
*
1688+
* @method Phaser.GameObjects.Components.Animation#remove
1689+
* @since 3.50.0
1690+
*
1691+
* @param {string} key - The key of the animation to remove.
1692+
*
1693+
* @return {Phaser.Animations.Animation} The Animation instance that was removed from this Sprite, if the key was valid.
1694+
*/
1695+
remove: function (key)
1696+
{
1697+
var anim = this.get(key);
1698+
1699+
if (anim)
1700+
{
1701+
if (this.currentAnim === anim)
1702+
{
1703+
this.stop();
1704+
}
1705+
1706+
this.anims.delete(key);
1707+
}
1708+
1709+
return anim;
1710+
},
1711+
14821712
/**
14831713
* Destroy this Animation component.
14841714
*
@@ -1489,7 +1719,12 @@ var Animation = new Class({
14891719
*/
14901720
destroy: function ()
14911721
{
1492-
this.animationManager.off(Events.REMOVE_ANIMATION, this.remove, this);
1722+
this.animationManager.off(Events.REMOVE_ANIMATION, this.globalRemove, this);
1723+
1724+
if (this.anims)
1725+
{
1726+
this.anims.clear();
1727+
}
14931728

14941729
this.animationManager = null;
14951730
this.parent = null;

0 commit comments

Comments
 (0)