@@ -10,6 +10,7 @@ var CustomMap = require('../structs/Map');
1010var EventEmitter = require ( 'eventemitter3' ) ;
1111var Events = require ( './events' ) ;
1212var GameEvents = require ( '../core/events' ) ;
13+ var GetFastValue = require ( '../utils/object/GetFastValue' ) ;
1314var GetValue = require ( '../utils/object/GetValue' ) ;
1415var Pad = require ( '../utils/string/Pad' ) ;
1516
@@ -168,6 +169,178 @@ var AnimationManager = new Class({
168169 return this . anims . has ( key ) ;
169170 } ,
170171
172+ /**
173+ * Create one, or more animations from a loaded Aseprite JSON file.
174+ *
175+ * Aseprite is a powerful animated sprite editor and pixel art tool.
176+ *
177+ * You can find more details at https://www.aseprite.org/
178+ *
179+ * To export a compatible JSON file in Aseprite, please do the following:
180+ *
181+ * 1. Go to "File - Export Sprite Sheet"
182+ *
183+ * 2. On the **Layout** tab:
184+ * 2a. Set the "Sheet type" to "Packed"
185+ * 2b. Set the "Constraints" to "None"
186+ * 2c. Check the "Merge Duplicates" checkbox
187+ *
188+ * 3. On the **Sprite** tab:
189+ * 3a. Set "Layers" to "Visible layers"
190+ * 3b. Set "Frames" to "All frames", unless you only wish to export a sub-set of tags
191+ *
192+ * 4. On the **Borders** tab:
193+ * 4a. Check the "Trim Sprite" and "Trim Cells" options
194+ * 4b. Ensure "Border Padding", "Spacing" and "Inner Padding" are all > 0 (1 is usually enough)
195+ *
196+ * 5. On the **Output** tab:
197+ * 5a. Check "Output File", give your image a name and make sure you choose "png files" as the file type
198+ * 5b. Check "JSON Data" and give your json file a name
199+ * 5c. The JSON Data type can be either a Hash or Array, Phaser doesn't mind.
200+ * 5d. Make sure "Tags" is checked in the Meta options
201+ * 5e. In the "Item Filename" input box, make sure it says just "{frame}" and nothing more.
202+ *
203+ * 6. Click export
204+ *
205+ * This was tested with Aseprite 1.2.25.
206+ *
207+ * This will export a png and json file which you can load using the Atlas Loader, i.e.:
208+ *
209+ * ```javascript
210+ * function preload ()
211+ * {
212+ * this.load.path = 'assets/animations/aseprite/';
213+ * this.load.atlas('paladin', 'paladin.png', 'paladin.json');
214+ * }
215+ * ```
216+ *
217+ * Once exported, you can call this method from within a Scene with the 'atlas' key:
218+ *
219+ * ```javascript
220+ * this.anims.createFromAseprite('paladin');
221+ * ```
222+ *
223+ * Any animations defined in the JSON will now be available to use in Phaser and you play them
224+ * via their Tag name. For example, if you have an animation called 'War Cry' on your Aseprite timeline,
225+ * you can play it in Phaser using that Tag name:
226+ *
227+ * ```javascript
228+ * this.add.sprite(400, 300).play('War Cry');
229+ * ```
230+ *
231+ * When calling this method you can optionally provide an array of tag names, and only those animations
232+ * will be created. For example:
233+ *
234+ * ```javascript
235+ * this.anims.createFromAseprite('paladin', [ 'step', 'War Cry', 'Magnum Break' ]);
236+ * ```
237+ *
238+ * This will only create the 3 animations defined. Note that the tag names are case-sensitive.
239+ *
240+ * @method Phaser.Animations.AnimationManager#createFromAseprite
241+ * @since 3.50.0
242+ *
243+ * @param {string } key - The key of the loaded Aseprite atlas. It must have been loaded prior to calling this method.
244+ * @param {string[] } [tags] - An array of Tag names. If provided, only animations found in this array will be created.
245+ *
246+ * @return {Phaser.Animations.Animation[] } An array of Animation instances that were successfully created.
247+ */
248+ createFromAseprite : function ( key , tags )
249+ {
250+ var output = [ ] ;
251+
252+ var data = this . game . cache . json . get ( key ) ;
253+
254+ if ( ! data )
255+ {
256+ return output ;
257+ }
258+
259+ var _this = this ;
260+
261+ var meta = GetValue ( data , 'meta' , null ) ;
262+ var frames = GetValue ( data , 'frames' , null ) ;
263+
264+ if ( meta && frames )
265+ {
266+ var frameTags = GetValue ( meta , 'frameTags' , [ ] ) ;
267+
268+ frameTags . forEach ( function ( tag )
269+ {
270+ var animFrames = [ ] ;
271+
272+ var name = GetFastValue ( tag , 'name' , null ) ;
273+ var from = GetFastValue ( tag , 'from' , 0 ) ;
274+ var to = GetFastValue ( tag , 'to' , 0 ) ;
275+ var direction = GetFastValue ( tag , 'direction' , 'forward' ) ;
276+
277+ if ( ! name )
278+ {
279+ // Skip if no name
280+ return ;
281+ }
282+
283+ if ( ! tags || ( tags && tags . indexOf ( name ) > - 1 ) )
284+ {
285+ // Get all the frames for this tag
286+ var tempFrames = [ ] ;
287+ var minDuration = Number . MAX_SAFE_INTEGER ;
288+
289+ for ( var i = from ; i <= to ; i ++ )
290+ {
291+ var frameKey = i . toString ( ) ;
292+ var frame = frames [ frameKey ] ;
293+
294+ if ( frame )
295+ {
296+ var frameDuration = GetFastValue ( frame , 'duration' , Number . MAX_SAFE_INTEGER ) ;
297+
298+ if ( frameDuration < minDuration )
299+ {
300+ minDuration = frameDuration ;
301+ }
302+
303+ tempFrames . push ( { frame : frameKey , duration : frameDuration } ) ;
304+ }
305+ }
306+
307+ tempFrames . forEach ( function ( entry )
308+ {
309+ animFrames . push ( {
310+ key : key ,
311+ frame : entry . frame ,
312+ duration : ( minDuration - entry . duration )
313+ } ) ;
314+ } ) ;
315+
316+ var totalDuration = ( minDuration * animFrames . length ) ;
317+
318+ if ( direction === 'reverse' )
319+ {
320+ animFrames = animFrames . reverse ( ) ;
321+ }
322+
323+ // Create the animation
324+ var createConfig = {
325+ key : name ,
326+ frames : animFrames ,
327+ duration : totalDuration ,
328+ yoyo : ( direction === 'pingpong' )
329+ } ;
330+
331+ var result = _this . create ( createConfig ) ;
332+
333+ if ( result )
334+ {
335+ output . push ( result ) ;
336+ }
337+ }
338+ } ) ;
339+ }
340+
341+ return output ;
342+ } ,
343+
171344 /**
172345 * Creates a new Animation and adds it to the Animation Manager.
173346 *
0 commit comments