Skip to content

Commit 98dc69e

Browse files
committed
Added in support for blending animations with addMix, getMix and removeMix.
1 parent 438fe3c commit 98dc69e

2 files changed

Lines changed: 168 additions & 2 deletions

File tree

src/animations/AnimationManager.js

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,17 @@ var AnimationManager = new Class({
8686
*/
8787
this.anims = new CustomMap();
8888

89+
/**
90+
* A list of animation mix times.
91+
*
92+
* See the {@link #setMix} method for more details.
93+
*
94+
* @name Phaser.Animations.AnimationManager#mixes
95+
* @type {Phaser.Structs.Map.<string>}
96+
* @since 3.50.0
97+
*/
98+
this.mixes = new CustomMap();
99+
89100
/**
90101
* Whether the Animation Manager is paused along with all of its Animations.
91102
*
@@ -122,6 +133,144 @@ var AnimationManager = new Class({
122133
this.game.events.once(GameEvents.DESTROY, this.destroy, this);
123134
},
124135

136+
/**
137+
* Adds a mix between two animations.
138+
*
139+
* Mixing allows you to specify a unique delay between a pairing of animations.
140+
*
141+
* When playing Animation A on a Game Object, if you then play Animation B, and a
142+
* mix exists, it will wait for the specified delay to be over before playing Animation B.
143+
*
144+
* This allows you to customise smoothing between different types of animation, such
145+
* as blending between an idle and a walk state, or a running and a firing state.
146+
*
147+
* Note that mixing is only applied if you use the `Sprite.play` method. If you opt to use
148+
* `playAfterRepeat` or `playAfterDelay` instead, those will take pririty and the mix
149+
* delay will not be used.
150+
*
151+
* To update an existing mix, just call this method with the new delay.
152+
*
153+
* To remove a mix pairing, see the `removeMix` method.
154+
*
155+
* @method Phaser.Animations.AnimationManager#addMix
156+
* @since 3.50.0
157+
*
158+
* @param {(string|Phaser.Animations.Animation)} animA - The string-based key, or instance of, Animation A.
159+
* @param {(string|Phaser.Animations.Animation)} animB - The string-based key, or instance of, Animation B.
160+
* @param {number} delay - The delay, in milliseconds, to wait when transitioning from Animation A to B.
161+
*
162+
* @return {this} This Animation Manager.
163+
*/
164+
addMix: function (animA, animB, delay)
165+
{
166+
var anims = this.anims;
167+
var mixes = this.mixes;
168+
169+
var keyA = (typeof(animA) === 'string') ? animA : animA.key;
170+
var keyB = (typeof(animB) === 'string') ? animB : animB.key;
171+
172+
if (anims.has(keyA) && anims.has(keyB))
173+
{
174+
var mixObj = mixes.get(keyA);
175+
176+
if (!mixObj)
177+
{
178+
mixObj = {};
179+
}
180+
181+
mixObj[keyB] = delay;
182+
183+
mixes.set(keyA, mixObj);
184+
}
185+
186+
return this;
187+
},
188+
189+
/**
190+
* Removes a mix between two animations.
191+
*
192+
* Mixing allows you to specify a unique delay between a pairing of animations.
193+
*
194+
* Calling this method lets you remove those pairings. You can either remove
195+
* it between `animA` and `animB`, or if you do not provide the `animB` parameter,
196+
* it will remove all `animA` mixes.
197+
*
198+
* If you wish to update an existing mix instead, call the `addMix` method with the
199+
* new delay.
200+
*
201+
* @method Phaser.Animations.AnimationManager#removeMix
202+
* @since 3.50.0
203+
*
204+
* @param {(string|Phaser.Animations.Animation)} animA - The string-based key, or instance of, Animation A.
205+
* @param {(string|Phaser.Animations.Animation)} [animB] - The string-based key, or instance of, Animation B. If not given, all mixes for Animation A will be removed.
206+
*
207+
* @return {this} This Animation Manager.
208+
*/
209+
removeMix: function (animA, animB)
210+
{
211+
var mixes = this.mixes;
212+
213+
var keyA = (typeof(animA) === 'string') ? animA : animA.key;
214+
215+
var mixObj = mixes.get(keyA);
216+
217+
if (mixObj)
218+
{
219+
if (animB)
220+
{
221+
var keyB = (typeof(animB) === 'string') ? animB : animB.key;
222+
223+
if (mixObj.hasOwnProperty(keyB))
224+
{
225+
// Remove just this pairing
226+
delete mixObj[keyB];
227+
}
228+
}
229+
else if (!animB)
230+
{
231+
// Remove everything for animA
232+
mixes.delete(keyA);
233+
}
234+
}
235+
236+
return this;
237+
},
238+
239+
/**
240+
* Returns the mix delay between two animations.
241+
*
242+
* If no mix has been set-up, this method will return zero.
243+
*
244+
* If you wish to create, or update, a new mix, call the `addMix` method.
245+
* If you wish to remove a mix, call the `removeMix` method.
246+
*
247+
* @method Phaser.Animations.AnimationManager#getMix
248+
* @since 3.50.0
249+
*
250+
* @param {(string|Phaser.Animations.Animation)} animA - The string-based key, or instance of, Animation A.
251+
* @param {(string|Phaser.Animations.Animation)} animB - The string-based key, or instance of, Animation B.
252+
*
253+
* @return {number} The mix duration, or zero if no mix exists.
254+
*/
255+
getMix: function (animA, animB)
256+
{
257+
var mixes = this.mixes;
258+
259+
var keyA = (typeof(animA) === 'string') ? animA : animA.key;
260+
var keyB = (typeof(animB) === 'string') ? animB : animB.key;
261+
262+
var mixObj = mixes.get(keyA);
263+
264+
if (mixObj && mixObj.hasOwnProperty(keyB))
265+
{
266+
return mixObj[keyB];
267+
}
268+
else
269+
{
270+
return 0;
271+
}
272+
},
273+
125274
/**
126275
* Adds an existing Animation to the Animation Manager.
127276
*
@@ -776,6 +925,8 @@ var AnimationManager = new Class({
776925
this.emit(Events.REMOVE_ANIMATION, key, anim);
777926

778927
this.anims.delete(key);
928+
929+
this.removeMix(key);
779930
}
780931

781932
return anim;
@@ -845,6 +996,7 @@ var AnimationManager = new Class({
845996
destroy: function ()
846997
{
847998
this.anims.clear();
999+
this.mixes.clear();
8481000

8491001
this.textureManager = null;
8501002

src/gameobjects/components/AnimationState.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -816,12 +816,26 @@ var AnimationState = new Class({
816816
{
817817
if (ignoreIfPlaying === undefined) { ignoreIfPlaying = false; }
818818

819+
var currentAnim = this.currentAnim;
820+
var parent = this.parent;
821+
819822
// Must be either an Animation instance, or a PlayAnimationConfig object
820823
var animKey = (typeof key === 'string') ? key : key.key;
821824

822-
if (ignoreIfPlaying && this.isPlaying && this.currentAnim.key === animKey)
825+
if (ignoreIfPlaying && this.isPlaying && currentAnim.key === animKey)
823826
{
824-
return this.parent;
827+
return parent;
828+
}
829+
830+
// Are we mixing?
831+
if (currentAnim && this.isPlaying)
832+
{
833+
var mix = this.animationManager.getMix(currentAnim.key, key);
834+
835+
if (mix > 0)
836+
{
837+
return this.playAfterDelay(key, mix);
838+
}
825839
}
826840

827841
this.forward = true;

0 commit comments

Comments
 (0)