Showing posts with label Spritor. Show all posts
Showing posts with label Spritor. Show all posts

Thursday, March 17, 2016

Phaser tutorial: Merging fonts into sprite atlas

 





Previous Phaser tutorials and articles:
Phaser: Typescript defs for Phaser Box2D plugin
Phaser tutorial: Spriter Pro features added to Spriter player for Phaser
Phaser tutorial: Using Phaser signals
Phaser tutorial: Breaking the (z-order) law!
Phaser tutorial: Phaser and Spriter skeletal animation
Phaser tutorial: DronShooter - simple game in Typescript - Part 3
Phaser tutorial: DronShooter - simple game in Typescript - Part 2
Phaser tutorial: adding 9-patch image support to Phaser
Phaser tutorial: DronShooter - simple game in Typescript - Part 1
Phaser tutorial: custom easing functions for tweening and easing functions with parameters
Phaser tutorial: sprites and custom properties for atlas frames
Phaser tutorial: manage different screen sizes
Phaser tutorial: How to wrap bitmap text


Introduction


 Everybody with at least short experience in game development came across sprite atlases. Its benefits are in merging multiple sprites into one large bitmap and so decreasing draw calls. We can simplify draw call as request to GPU to draw something with some set of parameters. One of these parameters is also texture. Changing any of parameters results into quite expensive setup on GPU side (flushing current work and doing setup for different set of parameters) - this is reason why to build larger textures made from individual sprites.
 Currently there is lot of tools, that help you with creating sprite atlas from individual sprites. But, when it comes to fonts, the situation starts to get complicated.

 For creating fonts I am using on-line tool Littera. This tool is great, but when you are exporting your font, you already get some atlas that contains your font characters. Alongside, you get file with characters metadata saying where in atlas is character positioned, how big it is, ... 
 Export from Littera can look like this:


 With metadata like this:

<font>
  <info face="MapNormal" size="40" bold="0" italic="0" charset="" unicode="" stretchH="100" smooth="1" aa="1" padding="2,2,2,2" spacing="0,0" outline="0"/>
  <common lineHeight="75" base="24" scaleW="42" scaleH="252" pages="1" packed="0"/>
  <pages>
    <page id="0" file="MapNormal.png"/>
  </pages>
  <chars count="10">
    <char id="48" x="2" y="2" width="18" height="24" xoffset="2" yoffset="3" xadvance="19" page="0" chnl="15"/>
    <char id="49" x="2" y="28" width="15" height="24" xoffset="0" yoffset="3" xadvance="13" page="0" chnl="15"/>
    <char id="50" x="2" y="54" width="21" height="25" xoffset="0" yoffset="2" xadvance="19" page="0" chnl="15"/>
    <char id="51" x="22" y="2" width="18" height="26" xoffset="1" yoffset="1" xadvance="17" page="0" chnl="15"/>
    <char id="52" x="2" y="81" width="20" height="25" xoffset="2" yoffset="3" xadvance="18" page="0" chnl="15"/>
    <char id="53" x="2" y="108" width="18" height="25" xoffset="1" yoffset="2" xadvance="16" page="0" chnl="15"/>
    <char id="54" x="2" y="135" width="20" height="27" xoffset="1" yoffset="0" xadvance="18" page="0" chnl="15"/>
    <char id="55" x="2" y="164" width="19" height="26" xoffset="1" yoffset="2" xadvance="12" page="0" chnl="15"/>
    <char id="56" x="2" y="192" width="19" height="28" xoffset="1" yoffset="1" xadvance="16" page="0" chnl="15"/>
    <char id="57" x="2" y="222" width="19" height="28" xoffset="1" yoffset="3" xadvance="18" page="0" chnl="15"/>
    <char id="32" x="0" y="0" width="0" height="0" xoffset="1" yoffset="3" xadvance="11" page="0" chnl="15"/>
  </chars>
  <kernings count="0"/>
</font>


 

Problem


 So, let's have some sprite atlas and above font created in Littera. Let's also imagine we have some object, that is made from sprites and text. This is exactly what map screen with map spots is in our upcoming game Pirates! - the match three game (graphics is made by Tomáš Kopecký):


 Every single map spot is object made from sprites and text (level number). Scene graph for it looks like this:


 Map has 65 level spots and drawing it takes 136 draw calls. 130 (65 * 2) of them is for map spots. It is very bad, but it is impact of switching between atlas with sprites and atlas with fonts. On above picture it is clear, that every time renderer renders single map spot, it has to switch texture twice.

 What we need is somehow merge font into our sprite atlas and keep valid font metadata. Then we will get rid of that texture switching and we will be able to decrease draw calls.


 

Solution


 Long time ago I made tool for creating sprite atlases. It is very old and it has messy code inside, not too good GUI and also name is messy - I call it sometimes PicOpt and more recently Spritor. Anyway, it has some nice features and I used it for all games I made. You can get it for free here. One of these nice features is, that it can do what we need. So, download it and follow next steps:

 Open Spritor tool and pres Ctrl+N to create new project. Give it name (it is not saved, it only created new project):
 

 Press Ctrl+A to add some sprites (individual .png images):


 Your screen should look similar to this:


 Now, pres Ctrl+A again and open you Littera font atlas. You need to have Littera .xml/.fnt file in the same directory. Also, do not forget to check "Is font" in bottom of dialog window:


 This will add Littera font atlas into your project. It will read through Littera metadata in .xml/.fnt and cut Littera font atlas into individual sprites. The role of metadata is not finished yet. It will play important role once again during export. You can now select type of export. To have one compatible with TexturePacker export, select format in top bar as this:


 (Btw, export just one line below ("JSON - TP + Properties") is adding custom properties, that you can add to your sprites in Spritor tool, into final export). You can now save your project by pressing Ctrl+S.

 It's time to make atlas. Go to menu and select Optimize -> Best Place:
 

 After some short time for optimiaztion, there will be created folder with name "export" and you will find several files there:
  • your atlas image,
  • your atlas metadata (in TexturePacker format),
  • one Littera metadata file (.xml or .fnt) for every font you merged into atlas. This file already has all character specs adjusted to positions in new atlas.
 This is how atlas from our walkthrough looks like:


Not finished yet - Phaser part


 As we have our assets ready, we can load it into Phaser and see what happes.

 Normally, you would load your font and atlas in preload method with code like:

this.load.atlas("Atlas", "assets/Atlas.png", "assets/Atlas.json");
this.load.bitmapFont("Font", "assets/Font.png", "assets/Font.xml");

 But in our case we already have fonts merged into atlas, so we do not need to load "Font.png" file. So, we will first change this to:

this.load.atlas("Atlas", "assets/Atlas.png", "assets/Atlas.json");
this.load.xml("Font", "assets/Font.xml");

 Then, when assets are loaded, in create method we have to build our font from loaded atlas and xml metadata. At first, it looks like easy task:

this.cache.addBitmapFont("MyFont", null, this.cache.getImage("Atlas"), this.cache.getXML("Font"), "xml");

 If you do above and run your game, You will see, that you can use "MyFont" in your game. It is taking characters from atlas, that is common with other sprites, but number of draw calls did not decreased! Something went wrong.

 Let's look into Phaser source. Method for addBitmapFont has this in the beginning:

    addBitmapFont: function (key, url, data, atlasData, atlasType, xSpacing, ySpacing) {

        var obj = {
            url: url,
            data: data,
            font: null,
            base: new PIXI.BaseTexture(data)
        };
           :
           :
           :

 And if we dive a little bit deeper into PIXI.WebGLSpriteBatch.prototype.flush() method we find this (shortened and lots of code omitted for clarity):

              :
              :
            nextTexture = sprite.texture.baseTexture;
              :
              :
        if ((currentBaseTexture !== nextTexture && !nextTexture.skipRender) || blendSwap || shaderSwap)
        {
            this.renderBatch(currentBaseTexture, batchSize, start);
              :
              :

 Batches are flushed based not on underlaying atlas image, but on baseTexture. As we have one atlas we have to achieve somehow to have the same baseTexture for atlas as well as for font. For this we will create our custom method that will add functionality to Phaser Cache class. Let's call it addBitmapFontFromImage. Code for it is mostly copy of original addBitmapFont:

* update for Phaser 2.7.3 and later * - when using jsonBitmapFont and xmlBitmapFont in code below, you have to pass two additional parameters for frame (null) and resolution (1).

module Utils {

    export class PhaserUtils {

        // -------------------------------------------------------------------------
        public static AddBitmapFontAddMethod(): void {

            Phaser.Cache.prototype["addBitmapFontFromImage"] = function addBitmapFont(key: string, url: string,
                imageName: string, atlasData: any, atlasType: string, xSpacing?: number, ySpacing?: number): void {

                var img = this.getImage(imageName, true);

                var obj = {
                    url: url,
                    data: img.data,
                    font: null,
                    base: img.base
                };

                if (xSpacing === undefined) { xSpacing = 0; }
                if (ySpacing === undefined) { ySpacing = 0; }

                if (atlasType === 'json') {
                    obj.font = Phaser.LoaderParser.jsonBitmapFont(atlasData, obj.base, xSpacing, ySpacing, null, 1);
                }
                else {
                    obj.font = Phaser.LoaderParser.xmlBitmapFont(atlasData, obj.base, xSpacing, ySpacing, null, 1);
                }

                this._cache.bitmapFont[key] = obj;

                this._resolveURL(url, obj);
            }
        }
    }
}

 Our new method is wrapped in special PhaserUtils class. Btw, I have this class filled with other small engine tweaks and in the very beginning of the game I call one or more static methods to apply these tweaks. You have to do the same - do it before you create game object!:

Utils.PhaserUtils.AddBitmapFontAddMethod();

 Now, replace line for creating font in create method with call to our new method:

this.cache["addBitmapFontFromImage"]("MyFont", null, "Atlas", this.cache.getXML("Font"), "xml");

 Call is using square brackets as we did not add our method into phaser.d.ts file. If you used standard call, you would get Typescript complaints.

 If you run your game now, you should see that number of draw calls decreased. In my case it went down from 136 to 6!!!


 

 Conclusion


 In our game we have in fact three different fonts for map spots - depends on whether spot is normal, finished, special battle spot... All three fonts contain only numbers. Instead of having three font atlases and one for sprites, we have only one for everything.
 This helps us to save resources, reduce draw calls and as the process of creating atlas is easy we do not get any overhead.




Saturday, April 11, 2015

Phaser tutorial: sprites and custom properties for atlas frames






Previous Phaser tutorials:
Phaser tutorial: manage different screen sizes
Phaser tutorial: How to wrap bitmap text


 Organizing sprites into atlases is important as it decreases loading time and increases performance of your game. You can create atlas by hand, but it would need lot of effort and it would be time consuming. Usually, you will use some specialised tool. In these days most used tool is Texture Packer. Unfortunately, this tool is just for creating atlases from individual frames and nothing more. It does not allow you to add additional properties to frames of your atlas.

 In this article I will show how to add additional properties to frames in Phaser engine, how to create atlas with these properties using SBC PicOpt tool and finally how to build flexible character with them. This is final result:


  Although, quality of the .gif animation image is low, you can see we will build Mr. Apple a let him do several movements: blink with eyes, jump, look suspiciously and shake with head.


Problems

 Mr. Apple is single object that hides small scene graph in it. The problem is how to build such a graph and how to do it with less effort. For this we will have to use Phaser groups and sprite and we will have to organize them in tree-like hierarchy. If you look at official Phaser examples you can find Group Transform example in which robot is build from parts. In listed code you can read:

    robot.create(90, 175, 'arm-l');
    robot.create(549, 175, 'arm-r');
    robot.create(270, 325, 'leg-l');
    robot.create(410, 325, 'leg-r');
    robot.create(219, 32, 'body');
    robot.create(335, 173,'eye');

 This is valid way how to build it, but the ugly part is, that you have to position each part manually in code. If you or your graphic change any part, it is probable, that you will have to rewrite this code to position adjusted part correctly.

 Second problem are anchors. For example in Unity each sprite has pivot point as a part of the definition. In Phaser you have to set anchor on sprite instance after it is created. It can turn into another try and miss game until you are happy with your anchor values. Anchors are between 0 and 1 and say how much the sprite image is shifted relative to its position. If your sprite has position 100, 100 and anchor is 0.5, 0.5 then the sprite is centered around position 100, 100.


 It is also necessary to say, that Texture Packer saves information on original frame size and anchors are related to it. If you had free space in the frame then this information is still there and anchor 0.5, 0.5 can look like this (that big guy is sprite from famous Golden Axe):


 Anchor also can be over 1 or under 0. Then the anchor point is outside of the frame, but it is still valid.

 Imagine you have sprites like this and you want to set anchor to points marked with red cross:

 It is obvious that for each sprite the anchor values will be different. You can avoid this by making all frames of the same size with lot of free space. But, as soon as you add third sprite which is wider or higher, you will have to adjust all previous frames and also recalculate new anchor values. Just try to guess what is value of this anchor - after several try and miss attempts you find it (of course, you can also calculate it if you measure anchor point distance from top left point and divide it with total frame width for x and height for y):


 Third problem is that in Texture Packer you can't add additional markers or extra information on frame and even if you adjusted export by hand or some tool (with for example anchors), then Phaser implementation of atlas loading would ignore it.

 So our problems are:
 - cumbersome positioning of group parts (sprites or nested groups),
 - cumbersome setting of anchors,
 - not possible to add additional properties to atlas frames



Mr. Apple

 As said earlier, we will build Mr. Apple. It will be build from Phaser groups and sprites. He will have shadow in the bottom, body and head with eyes, eyelids, glasses over it. To animate him later, shadow, body and head will have to be independent parts. If he is jumping, then shadow stays on ground, but rest is in the air. Here is scene graph of Mr. Apple:
 Groups are in red and sprites in blue. Top node is Mr. Apple himself so in game you can create several instances and moving it moves all subsequent parts. This is graphical representation of the same scene graph. Groups are that dashed rectangles:


 World is Phaser world and it just says that Mr. Apple is placed somewhere... From this analysis we can see, that that it would be fine if we had two additional information on each frame. The red cross is anchor point of sprite and the blue cross is position of next item. It is chained together: red cross position of sprite overlaps blue cross position of previous sprite. The "T" shaped sprite is glasses as we need to draw it over eyes and eyelids. More, eyelids are animated to make blinks.



Sprite atlas with additional properties

 Now, we will solve our first two problems. We will create atlas and add information for red and blue crosses. Download SBC PicOpt tool here. It is java application. I wrote it long time ago and the code inside is really very very ugly and bad. If you can imagine any wrong thing in writing code, be sure it is there. Every time I need something I adjust it and it is pure mess now. But, it still works and it is great for me. It can create even very big atlases with hundreds of frames in quite a short time. It can also scale sprites (there is global scale and also individual scales for each sprite) and do lot of other things. One of these thing is, that you can add custom properties to sprites.

 If you need short intro into it, read this article. It is for older version, but still valid (new features added since).

 Also download this image (right click and save) with Mr. Apple's parts:

 If you wonder, what is the magenta grid, it is way how to split frames. The tool will analyze the image and cut sprites from it (it can also load individual images without grid).

 In case, you have both the tool and image downloaded and you ran the tool, pres ctrl+N. It is new project. Navigate, where you want to save it and give it name (this time the file is not yet created, only path is remembered ... I warned you, the tool is messy :-)). Now, press ctrl+A or (or go to Bitmap -> Add bitmap and open saved image. Time to save: pres ctrl+S. It creates save file in .xml format. You should see this:


 There is red "anchor" point and property "Offset". Offset says how many pixels is top left corner of trimmed sprite from red "anchor" point. This is not exactly what we want, but during export it will be recalculated into anchor information suitable for Phaser. Red point is always fixed - if you want to move it, you have to move sprite itself. In export section there are "JSON - Texture Packer" and "JSON - TP+Properties" items. The first one mimics Texture Packer export and Phaser can load it without problems as JSON Array. The second is the same, but it adds additional properties on each frame - currently the anchor information. This is example export for one frame with "JSON - Texture Packer":

{
 "filename": "head",
 "frame": {"x":1,"y":1,"w":74,"h":82},
 "rotated": false,
 "trimmed": true,
 "spriteSourceSize": {"x":0,"y":1,"w":74,"h":82},
 "sourceSize": {"w":74,"h":86}
}

And this is example for "JSON - TP+Properties":

{
 "filename": "_testChar",
 "frame": {"x":1,"y":1,"w":74,"h":82},
 "rotated": false,
 "trimmed": true,
 "spriteSourceSize": {"x":0,"y":1,"w":74,"h":82},
 "sourceSize": {"w":74,"h":86},
 "anchor": {"w":0.49324,"h":0.50581},
}

 Notice the red line with calculated anchor.

 Now is time to select export type to "JSON - TP+Properties" and to name each of our frames. Name them in text field above properties on left like this:
  • body: "body",
  • eyelids: "blick_0", "blick_1", "blick_2", "blick_3", "blick_4",
  • eyes: "eyes",
  • body: "body",
  • shadow: "shadow",
  • glasses: "glasses"
 Press ctrl+P or select Sprite -> Sprite Properties and add new point property with name "nextItem" like this:


 This adds new blue point into main area. This additional property point can be dragged with mouse. This is our blue cross. Now, you can place red and blue points like it is on Mr. Apple's scene graph. Or you may load SBC PicOpt project, where sprites are renamed and markers placed here.

 Finally, choose Optimize -> Best Place (name of atlas making method). this will create new directory with name "export" and two files in it: .png with atlas and .json with JSON Array. Atlas may look like this, but you can have the sprites on different positions:

 In .json each frame has now this structure:

{
 "filename": "head",
 "frame": {"x":1,"y":1,"w":74,"h":82},
 "rotated": false,
 "trimmed": true,
 "spriteSourceSize": {"x":0,"y":1,"w":74,"h":82},
 "sourceSize": {"w":74,"h":86},
 "anchor": {"w":0.49324,"h":0.95930},
 "nextitem": {"w":0,"h":-35}
}

 Now, we have all assets prepared and we need to persuade Phaser to work with new frame properties.



Code

 Code will be written in Typescript and you can get whole final project here (pressing q, w, e, r will force Mr. Apple to do some things).

 Phaser can process atlas data in JSON Array, JSON Hash and XML. Each type of data is processed in separate routine in animation/AnimationParser.js source. All these routines do, is that it builds frames (Phaser.Frame) from loaded atlas data. And all we will do, is change this to add our custom callback on every created frame. Here is new class PhaserUtils in module Utils (we will change only JSON Array loading as this is type exported from SBC PicOpt tool):

module Utils {

    export class PhaserUtils {

        // -------------------------------------------------------------------------
        public static ChangeAnimationPhaserJSONData(
            aCallback: (aFrame: Phaser.Frame, aData: any) => void) {

            Phaser.AnimationParser["myCallback"] = aCallback;

            // new implementation of JSON array textureatlas loading routine
            Phaser.AnimationParser.JSONData = function (aGame, aJSON, aCacheKey): Phaser.FrameData {

                //  Malformed?
                if (!aJSON['frames']) {
                    console.warn("Phaser.AnimationParser.JSONData: Invalid Texture Atlas JSON given, missing 'frames' array");
                    console.log(aJSON);
                    return;
                }

                //  Let's create some frames then
                var data = new Phaser.FrameData();

                //  By this stage frames is a fully parsed array
                var frames = aJSON['frames'];
                var newFrame;

                for (var i = 0; i < frames.length; i++) {
                    var uuid = aGame.rnd.uuid();

                    newFrame = data.addFrame(new Phaser.Frame(
                        i,
                        frames[i].frame.x,
                        frames[i].frame.y,
                        frames[i].frame.w,
                        frames[i].frame.h,
                        frames[i].filename,
                        uuid.toString()
                        ));

                    PIXI.TextureCache[uuid] = new PIXI.Texture(PIXI.BaseTextureCache[aCacheKey], <PIXI.Rectangle> {
                        x: frames[i].frame.x,
                        y: frames[i].frame.y,
                        width: frames[i].frame.w,
                        height: frames[i].frame.h
                    });

                    if (frames[i].trimmed) {
                        newFrame.setTrim(
                            frames[i].trimmed,
                            frames[i].sourceSize.w,
                            frames[i].sourceSize.h,
                            frames[i].spriteSourceSize.x,
                            frames[i].spriteSourceSize.y,
                            frames[i].spriteSourceSize.w,
                            frames[i].spriteSourceSize.h
                            );
                    }

                    // HERE is change from default implementation
                    Phaser.AnimationParser["myCallback"](newFrame, frames[i]);
                }

                return data;
            }
        }
    }
}

 It is almost pure copy-paste. In top we add myCallback property to original Phaser.AnimatonParser class and we assign parameter passed into method to it. This parameter is function that takes new fresh Phaser.Frame and JSON data and will do some additional processing to default one. Next, we replace implementation of Phaser.AnimationParser.JSONData with copy of original implementation (I had to do small changes to avoid typescript errors - marked in red) and in the bottom we add call to our callback method.

 In game class we first call this PhaserUtility method and we pass it "additionalFramProperties". This is the callback method that will get called on every atlas frame created. In it we can finally read our new anchor and nextItem properties. From now on every atlas frame will have it. As we can change this callback, we can have different properties for different atlases!

module CustomFrames {

    export class Game extends Phaser.Game {
        // -------------------------------------------------------------------------
        constructor() {
            // change default loading routine for JSON Array
            var callback = this.additionalFrameProperties;
            Utils.PhaserUtils.ChangeAnimationPhaserJSONData(callback);

            // calculate screen dimensions
            var screenDims = Utils.ScreenUtils.calculateScreenMetrics(800, 500, Utils.Orientation.LANDSCAPE, 800, 500);

            super(screenDims.gameWidth, screenDims.gameHeight, Phaser.AUTO, "content", null /* , transparent, antialias, physicsConfig */);
            
            // states
            this.state.add('Boot', Boot);

            // start
            this.state.start('Boot');
        }

        // -------------------------------------------------------------------------
        public additionalFrameProperties(aFrame: Phaser.Frame, aData: any): void {
            // anchor
            if (aData.anchor) {
                aFrame["anchorX"] = aData.anchor.w;
                aFrame["anchorY"] = aData.anchor.h;
            }

            // next tem
            if (aData.nextitem) {
                aFrame["nextItemX"] = aData.nextitem.w;
                aFrame["nextItemY"] = aData.nextitem.h;
            }
        }
    }
}

 In class MrApple we build Mr. Apple with all its groups and sprites. The constructor method could be written in more compact way, but I left it like it is for easy reading. You can go step by step and see which part is added, where it is positioned:

module CustomFrames {

    export class MrApple extends Phaser.Group {

        private _game: Phaser.Game;

        private _shadow: Phaser.Sprite;
        private _character: Phaser.Group;
        private _body: Phaser.Sprite
        private _top: Phaser.Group;
        private _head: Phaser.Sprite;
        private _eyes: Phaser.Sprite;
        private _blick: Phaser.Sprite;
        private _glasses: Phaser.Sprite;

        // -------------------------------------------------------------------------
        constructor(aGame: Phaser.Game) {
            super(aGame, null, "MrApple group");

            // to save typing
            this._game = aGame;
            var cache: Phaser.Cache = aGame.cache;
            var add: Phaser.GameObjectFactory = aGame.add;

            // shadow
            this._shadow = add.sprite(0, 0, "MrApple", "shadow", this);
            var shadowFrame: Phaser.Frame = cache.getFrameByName("MrApple", "shadow");
            this._shadow.anchor.setTo(shadowFrame["anchorX"], shadowFrame["anchorY"]);

            // character group
            this._character = add.group(this, "character group");
            this._character.position.setTo(shadowFrame["nextItemX"], shadowFrame["nextItemY"]);

            // sprite body
            this._body = add.sprite(0, 0, "MrApple", "body", this._character);
            var bodyFrame: Phaser.Frame = cache.getFrameByName("MrApple", "body");
            this._body.anchor.setTo(bodyFrame["anchorX"], bodyFrame["anchorY"]);

            // top group
            this._top = add.group(this._character, "top group");
            this._top.position.setTo(bodyFrame["nextItemX"], bodyFrame["nextItemY"]);

            // head
            this._head = add.sprite(0, 0, "MrApple", "head", this._top);
            var headFrame: Phaser.Frame = cache.getFrameByName("MrApple", "head");
            this._head.anchor.setTo(headFrame["anchorX"], headFrame["anchorY"]);

            var nextX: number = headFrame["nextItemX"];
            var nextY: number = headFrame["nextItemY"];

            // eyes
            this._eyes = add.sprite(nextX, nextY, "MrApple", "eyes", this._top);
            var eyesFrame: Phaser.Frame = cache.getFrameByName("MrApple", "eyes");
            this._eyes.anchor.setTo(eyesFrame["anchorX"], eyesFrame["anchorY"]);

            // blick
            this._blick = add.sprite(nextX, nextY, "MrApple", "blick_0", this._top);
            var blickFrame: Phaser.Frame = cache.getFrameByName("MrApple", "blick_0");
            this._blick.anchor.setTo(blickFrame["anchorX"], blickFrame["anchorY"]);

            // glasses
            this._glasses = add.sprite(nextX, nextY, "MrApple", "glasses", this._top);
            var glassesFrame: Phaser.Frame = cache.getFrameByName("MrApple", "glasses");
            this._glasses.anchor.setTo(glassesFrame["anchorX"], glassesFrame["anchorY"]);


            // add animations to blick sprite
            this._blick.animations.add("blick_idle", Phaser.Animation.generateFrameNames("blick_", 0, 0, "", 1), 30, true);
            this._blick.animations.add("blick_blick", Phaser.Animation.generateFrameNames("blick_", 0, 4, "", 1), 30, false);
        }

// ... various tween methods to force Mr.Apple do funny things ...

    }
}

 In the listing I omitted various methods that are run when q, w, e, r keys are pressed. These methods are playing with tweens and are not subject of this article. You can examine them in final project source.


Conculsion

 Mr. Apple is build. If you need to reposition some parts, you can do it in editor, export assets and your code will still work. With small adjustments you can change MrApple class to more universal FruitCharacter class and add Mrs. Pear and other characters like on this image (image is from game Fruit Dating which is puzzle game currently available for iOS and Android and graphics is by Tomas Kopecky):




Download final project here: CustomFrames.zip