12 March 2014

First post on 2014. YAY!!

Not a tutorial for this post. Just want to inform all of my blog readers and visitors, especially the ones that looking to buy my game assets, that starting on February 2014, I partnered with CartoonSmart to release my items as a bundle on their site, called The Super Sprite Bundle.
Check it out:

2d game asset sprite tile set
Click the image to see detailed information for this pack.

As you can see, it only $39 and you get several items at once. From platformer tilesets, game GUI packs, and character spritesheets are included.
And the most importantly, it’s coming as a single license only. No need to messed up with licenses provided by marketplace sites which sometimes not quite suitable for game developers. So for anyone who looking for affordable game assets, this Sprite Bundle definitely what are you looking for.

We’re planning to release another bundle next month. See what will happen…

I also opened my shop for those game assets on CreativeMarket.com as alternative for GraphicRiver.net if you’re looking for more affordable price for my game assets. $1 off, no surcharge, & one price for both personal & commercial use.

Some samples:

2d game gui pack

https://creativemarket.com/pzUH/21098-Characters-Spritesheets-9

And many more.

Exact same as the one that available on GraphicRiver though...

If it still can’t make you satisfied, well, probably we can make our own deal instead. Simply drop me a mail.

10 March 2014

I’m enjoying diving deeper to Box2D at the moments. And now I want to share about Raycast. As well as how to make a Spiderman, Worm, or Bionic Commando-like rope swing, because it’s one of implementation of Raycast.

spider-man-meme-rope

Raycast
Raycasting is simply create a straight line between two point. Sound pretty simple, but it can be quite useful. Let say you want your AI character have a Line of Sight (LOS) function that will detect what objects are on his sight. Another example if you want to slice an object. Or probably simulate a light ray. I think it can be used on another scenario, that I haven’t discover yet.

I won’t explain about Box2D raycast feature here, as I also quite new to this thing. If you want more detailed explanation, maybe you can google that.

So this is my Ray class that wrapped Box2D raycast function and adds a feature to draw the line on the screen. Box2D debug draw doesn’t render the raycast graphic, so you need to create it by yourself.

package  
{    
    public class Ray     
    {     
        public static const RAY_CAST:String = "ray_cast";     
        public static const RAY_CAST_ONE:String = "ray_cast_one";     
        public static const RAY_CAST_ALL:String = "ray_cast_all";     
      
        public var startPoint:b2Vec2;     
        public var endPoint:b2Vec2;     
        
        public var onContact:Signal;     
        
        public var fraction:Number = 1;     
        
        public var fixture:b2Fixture;     
        public var fixtures:Vector.<b2Fixture>;     
        
        private var sprite:CitrusSprite;     
        private var shape:Shape;     
        
        private var box2D:Box2D;     
        
        private var type:String;     
        
        private var lineGraphic:Boolean = true;     
        
        public function Ray(box2D:Box2D, type:String = RAY_CAST, lineGraphic:Boolean = true)     
        {     
            this.box2D = box2D;     
            
            this.type = type;     
            this.lineGraphic = lineGraphic;     
            
            if (this.lineGraphic)     
            {     
                sprite = new CitrusSprite("raySprite");     
                CitrusEngine.getInstance().state.add(sprite);     
                
                shape = new Shape();     
            }     
            
            startPoint = new b2Vec2();     
            endPoint = new b2Vec2();     
          
            if (this.type == RAY_CAST)     
            {     
                onContact = new Signal(b2Fixture, b2Vec2, b2Vec2);     
            }     
        }     
        
        public function createRay():void     
        {     
            startPoint.x = startPoint.x / box2D.scale;     
            startPoint.y = startPoint.y / box2D.scale;     
            
            endPoint.x = endPoint.x / box2D.scale;     
            endPoint.y = endPoint.y / box2D.scale;     
            
            switch (type)     
            {     
                case RAY_CAST:     
                    box2D.world.RayCast(rayCastHandler, startPoint, endPoint);     
                    break;     
                
                case RAY_CAST_ONE:     
                    fixture = box2D.world.RayCastOne(startPoint, endPoint);     
                    break;     
                
                case RAY_CAST_ALL:     
                    fixtures = box2D.world.RayCastAll(startPoint, endPoint);     
                    break;     
            }     
            
            drawLine();     
        }     
        
        private function rayCastHandler(fixture:b2Fixture, intersection:b2Vec2, normal:b2Vec2, fraction:Number):Number     
        {     
            endPoint.x = intersection.x;     
            endPoint.y = intersection.y;     
            
            onContact.dispatch(fixture, intersection, normal);     
            
            return this.fraction;     
        }     
        
        private function drawLine():void     
        {     
            if (!lineGraphic)     
            {     
                return;     
            }     
            
            shape.graphics.clear();     
            shape.graphics.lineStyle(1);     
            shape.graphics.moveTo(startPoint.x * box2D.scale, startPoint.y * box2D.scale);     
            shape.graphics.lineTo(endPoint.x * box2D.scale, endPoint.y * box2D.scale);     
            
            sprite.view = shape;     
        }     
        
        public function destroy():void     
        {     
            if (type == RAY_CAST)     
            {     
                onContact.removeAll();     
                onContact = null;     
            }     
            
            if (lineGraphic)     
            {     
                shape = null;     
                sprite = null;     
            }     
            
            startPoint = null;     
            endPoint = null;     
        }     
    }     
}

I’m using Starling Graphic Extension here, because by default, Starling doesn’t have a graphics API that can be used to draw vector objects: line, square, circle, etc like Flash.

There are three constant, it will define what type of raycast will be used. RAY_CAST is the default, RAY_CAST_ONE will return first fixture that intersect with the ray, and RAY_CAST_ALL will return all fixtures.
Also there are two point, startPoint and the endPoint.

Fixture variable will hold a reference of the fixture returned if we use RaycastOne. And fixtures variable, a vector that hold reference of fixtures returned by RaycastAll.

Fraction is still a mystery for me. But from what I read somewhere, it’s used by the default Raycast to determine its behaviour. Set it to 0, it will stop at the first target on contact. Set it to 1 it will return all fixtures on contact. Set it to –1 it will ignore everything.

Other variables are self explanatory, I think.

Let’s jump to the createRay() method instead of the constructor, as it’s pretty clear already. In the createRay() method, it convert the startPoint and endPoint to box2D measurement, by simply divide it by box2D scale property. Then we can do the raycasting, based on the raycast type. 
The default raycast will need a callback function, RayCastHandler(). While the others aren’t.

On the rayCastHandler() method, you’ll get information about what fixture that intersect the ray, it’s intersection & normal point, and the fraction. Btw, I still don’t understand what’s fraction function parameter supposed to do. :\

I have a signal here, that will be dispatched when the ray hit something. It will contain all parameter, except fraction.

Okay, we’ve got the raycast wrapper set-up, now we need to implement it on the Hero class. I create a CustomHero class that extends CE default Hero class:

package    
{     
    public class CustomHero extends Hero     
    {     
        private var LOS:Ray;     
        
        public function CustomHero(name:String, params:Object = null)     
        {     
            super(name, params);     
            
            LOS = new Ray(_box2D);     
            LOS.fraction = 0;     
            LOS.onContact.add(LOSContactHandler);     
        }     
        
        override public function update(timeDelta:Number):void     
        {     
            super.update(timeDelta);     
            
            LOS.startPoint.x = x;     
            LOS.startPoint.y = y;     
            
            LOS.endPoint.x = x + 200;     
            LOS.endPoint.y = y;     
            
            if (_inverted)     
            {     
                LOS.endPoint.x = x - 200;     
            }     
            
            LOS.createRay();            
        }     
        
        private function LOSContactHandler(fixture:b2Fixture, intersection:b2Vec2, normal:b2Vec2):void     
        {     
            GameState(_ce.state).setText("target: " + fixture.GetBody().GetUserData().name);     
        }     
    }     
}


Simply create a Ray object called LOS. It will use the default RayCast. And set the fraction to 0, so it will return the first object that intersect with the ray.

Because we want to create a LOS, so it will need stick to the hero all the time, and have a fixed length. On the update() method, set the startPoint to the exact same position as the hero. And the add the length value (200) to the hero x position. Make sure it will also inverted when the hero facing opposite direction. Then call the createRay() function. On the LOSContactHandler(), it’ll just write the object’s name to a TextField.

An the result is something like this:


Move around, and the text field will tell you the object’s name that collide with the ray.
Btw, you can click & hold on the ceiling platform to activate the spidey rope.
How to create that? Just keep reading… Open-mouthed smile

Spiderman Swing


bio
Not Spiderman

The idea just to create a distance joint between the hero to a specified point. To get the target position, we use the raycast function. It will create a ray between hero and the mouse position. If there are a fixture being intersect with the ray, then it’s the target point.

I’ll just paste my GameState code here, with a lot of unnecessary code omitted:

package    
{     
    public class GameState extends StarlingState     
    {     
        private var jointRay:Ray;     
        
        private var jointDef:b2DistanceJointDef;     
        private var joint:b2DistanceJoint;     
        
        private var jointLine:Shape;     
        private var jointSprite:CitrusSprite;     
        
        private var mouseHold:Boolean = false;
         
        public function GameState()     
        {     
            super();     
        }     
        
        override public function initialize():void     
        {     
            super.initialize();
             
            jointRay = new Ray(box2D);     
            jointRay.fraction = 0;     
            jointRay.onContact.add(jointRayContact);         
          
            jointSprite = new CitrusSprite("jointSprite");     
            add(jointSprite);     
            
            jointLine = new Shape();
             
            stage.addEventListener(TouchEvent.TOUCH, click);     
        }     
        
        private function click(event:TouchEvent):void     
        {     
            var touch:Touch = event.getTouch(stage);     
            
            if (touch)     
            {     
                if (touch.phase == TouchPhase.BEGAN)     
                {     
                    var posX:int = event.getTouch(event.currentTarget as DisplayObject).globalX;     
                    var posY:int = event.getTouch(event.currentTarget as DisplayObject).globalY;     
                    var worldPos:Point = ((view as StarlingView).viewRoot as Sprite).globalToLocal(new Point(posX, posY));     
                    
                    var hero:CustomHero = getObjectByName("hero") as CustomHero;     
                    
                    jointRay.startPoint.x = hero.x;     
                    jointRay.startPoint.y = hero.y;     
                    jointRay.endPoint.x = worldPos.x;     
                    jointRay.endPoint.y = worldPos.y;     
                    
                    jointRay.createRay();     
                    
                    mouseHold = true;     
                }     
                else if (touch.phase == TouchPhase.ENDED)     
                {     
                    if (joint)     
                    {     
                        var box2D:Box2D = getObjectByName("box2D") as Box2D;     
                        box2D.world.DestroyJoint(joint);     
                        
                        joint = null;     
                        jointDef = null;     
                        
                        jointLine.graphics.clear();     
                    }     
                    
                    mouseHold = false;     
                }     
            }     
        }     
        
        override public function update(timeDelta:Number):void     
        {     
            super.update(timeDelta);     
            
            if (mouseHold)     
            {     
                if (joint)     
                {                    
                    var box2D:Box2D = getObjectByName("box2D") as Box2D;     
                    
                    joint.SetLength(joint.GetLength() - (5 / box2D.scale));     
                    
                    drawLine();     
                }     
            }     
        }     
        
        private function drawLine():void     
        {     
            var box2D:Box2D = getObjectByName("box2D") as Box2D;     
            
            jointLine.graphics.clear();     
            jointLine.graphics.lineStyle(2, 0xFF0000);     
            jointLine.graphics.moveTo(joint.GetAnchorA().x * box2D.scale, joint.GetAnchorA().y * box2D.scale);     
            jointLine.graphics.lineTo(joint.GetAnchorB().x * box2D.scale, joint.GetAnchorB().y * box2D.scale);     
            
            jointSprite.view = jointLine;     
        }     
        
        private function jointRayContact(fixture:b2Fixture, intersec:b2Vec2, normal:b2Vec2):void     
        {     
            var hero:CustomHero = getObjectByName("hero") as CustomHero;     
            var box2D:Box2D = getObjectByName("box2D") as Box2D;     
            
            if (joint)     
            {     
                box2D.world.DestroyJoint(joint);     
            }     
            
            jointDef = new b2DistanceJointDef();     
            jointDef.Initialize(hero.body, fixture.GetBody(), hero.body.GetWorldCenter(), intersec);     
            
            joint = box2D.world.CreateJoint(jointDef) as b2DistanceJoint;     
        }
    }    
}

Initialize all the necessary objects: Ray, DistanceJointDef, DistanceJoint. And objects for the graphical representation of the hook: Shape & CitrusSprite.
We use default RayCast mode, and fraction of 0. Don’t forget to add touch event to the stage.

Jump to the click() method. To simulate a mouse hold event on Starling we need to detect the phase. Set the mouseHold property to true when it’s in Began phase. Otherwise, set it to false when in Ended phase.

In the Began phase, we create a ray. If the ray intersect with a fixture, then surely it will fire a signal. Catch it with jointRayContact() method and create the DistanceJoint object between the hero to the intersection point.
In the Ended phase, if a joint is exists, we need to destroy them. And also remove the graphical representation.

I also shorten the rope when players holding the mouse button. Just take a look on the update() method. I reduce the joint length 5 pixel per frame. Don’t forget to divide it with box2D scale factor.

DrawLine() method, well, just to draw a red line as a graphical representation for the joint.

Done
Ok, you can download the source code here:

download

08 March 2014

Just simple tutorial for this time. I’ll show how to make a character that can aim with mouse and shoot projectiles. And I choose arrow instead of straight bullet because arrow is a little bit more advanced than bullet. But if you want your character to shoot bullet, rocket, or grenade, you can simply modify the implementation. Should be not quite much difference.

orc_archers_squad_by_daroz-d5oi7u9

Start with creating the CE project. Create MainClass and the GameState. Create floor & walls. Not much to explain here, as all of them are just default CE objects.

Open the GameState class, then inside the initialize() method, before the box2D initialization code, add this lines:

PhysicsCollisionCategories.Add("hero");    
PhysicsCollisionCategories.Add("bullet");

Since the bullet is not a sensor, we need to define a collision group for both Hero and Arrow object, so the arrow will not collide with the hero. As you can see, we create two categories, “hero” and “bullet”.

Create a new class extend CE box2D Hero class. Give it name CustomHero. After that override its defineFixture() method.

override protected function defineFixture():void  
{     
     super.defineFixture();     
            
     _fixtureDef.filter.categoryBits = PhysicsCollisionCategories.Get("hero");     
     _fixtureDef.filter.maskBits = PhysicsCollisionCategories.GetAllExcept("bullet");     
}    

We put it to ‘'hero” categories. Then maskBits is to select which object categories that can collide with this. In this case, we make the hero can collide with all objects, except any objects in the “bullet” category.

Create a new class extends CE box2D Crate class. Name it Arrow. Why extend crate? Well, I’m just lazy to create a new object from Box2DPhysicsObject class. But the arrow has quite same characteristic with crate, so why not?

public function Arrow(name:String, params:Object = null)    
{     
     super(name, params);     
            
     _beginContactCallEnabled = true;     
     updateCallEnabled = true;     
}     
        
override protected function defineFixture():void     
{     
     super.defineFixture();     
            
     _fixtureDef.density = .1;     
            
     _fixtureDef.filter.categoryBits = PhysicsCollisionCategories.Get("bullet");     
     _fixtureDef.filter.maskBits = PhysicsCollisionCategories.GetAllExcept("hero", "bullet");     
}

Inside the constructor, set both _beginContactCallEnabled & updateCallEnabled property to true. It will make the object respond when on contact. And it will enable its update() method. We also override the defineFixture() method to define its collision category things.

Shooting
Ok, move back to GameState class and now you can initialize the hero. Also make the stage respond touch input:

var hero:CustomHero = new CustomHero("hero", {width: 50, height: 80});    
hero.x = 100;     
hero.y = 100;     
add(hero);

             
stage.addEventListener(TouchEvent.TOUCH, mouseClick);

And this is what happen when you touch the screen:

private function mouseClick(event:TouchEvent):void    
{     
     var touchVec:Vector.<Touch> = event.getTouches(stage, TouchPhase.ENDED);     
            
     if (touchVec.length > 0)     
     {     
         var posX:int = event.getTouch(event.currentTarget as DisplayObject).globalX;     
         var posY:int = event.getTouch(event.currentTarget as DisplayObject).globalY;  
                 
         var worldPos:Point = ((view as StarlingView).viewRoot as Sprite).globalToLocal(new Point(posX, posY));     
                
         var hero:CustomHero = getObjectByName("hero") as CustomHero;     
                
         var angle:Number = Basic.getPointAngle(hero.x, hero.y, worldPos.x, worldPos.y);     
                
         var distX:Number = Math.abs(hero.x - worldPos.x);            
         var distY:Number = Math.abs(hero.y - worldPos.y);            
         var powerX:Number = distX / 400;     
         var powerY:Number = distY / 200;     
                
         var arrow:Arrow = new Arrow("bullet", {width: 40, height: 10});     
         arrow.x = hero.x;     
         arrow.y = hero.y;     
         arrow.rotation = Basic.radianToDegree(angle);     
         add(arrow);                
                
         var xDir:Number = Math.cos(angle) * powerX;     
         var yDir:Number = Math.sin(angle) * powerY;     
                
         arrow.body.ApplyImpulse(new b2Vec2(xDir, yDir), arrow.body.GetWorldCenter());     
     }     
}

First things first, to detect clicking or tapping, make sure there are touches that ‘ended’ already. If it’s exists then we can execute the shooting action.

We need to know the coordinates where the click happen with posX & posY variables. And then convert them to game state coordinates, worldPos Point variable.

Then get the angle between the click and you’re hero. I’m using my utility class here to do that. If you want to know how it works, there are a lot of reference about that on the web. It just calculate the x & y distance between the objects, then using atan2() to get the angle. Quite simple, but I’m too lazy to remember & rewrite it. Smile with tongue out

I designed the power of launched arrow based on the distance between the click to the hero. That’s what distX, distY, powerX, and powerY variables mean. The value of 400 & 500 on powerX and powerY are just the hardcoded one to get my desired power result.

Then we can create the arrow. Just initialize it like the other CE objects. But we need to specify its rotation using the angle we’ve got before. Convert it to degree value first. Yet again, I’m using my utility class.
Additional note: Replace the arrow object with built-in CE Missile object if you want to create a hero that shoot a straight bullet. And ignore the remaining code below.

The arrow won’t do anything for now. So let’s apply some impulse on it. Before that, define the x and y direction of the impulse, just see the xDir and yDir variables. Then using them as a vector parameter on applyImpulse() method.

Almost done. Open the Arrow class. Override the update() method:

override public function update(timeDelta:Number):void   
{    
     super.update(timeDelta);    
            
     var flyingAngle:Number=Math.atan2(body.GetLinearVelocity().y, body.GetLinearVelocity().x);    
     body.SetAngle(flyingAngle);    
}

We need to define the flyingAngle, so we’ll get a realistic flying arrow effect. Using atan2() and the arrow velocity as parameter to get the current angle.
Additional note: Remove that line, then you’ll have a stone or grenade throwing effect. Probably add a constant small rotation to get better effect.

Sticking Arrow
To get a even more realistic effect, then we can make the arrow that will stick on the target. To do that, it just using a weld joint.
Open the Arrow class, and override the handleBeginContact() method:

override public function handleBeginContact(contact:b2Contact):void   
{    
    var collider:Box2DPhysicsObject = Box2DUtils.CollisionGetOther(this, contact) as Box2DPhysicsObject;    
            
    var jointDef:b2WeldJointDef = new b2WeldJointDef();    
    jointDef.Initialize(body, collider.body, body.GetWorldCenter());    
            
    var joint:b2WeldJoint = b2WeldJoint(_box2D.world.CreateJoint(jointDef));    
            
    updateCallEnabled = false;    
            
    setTimeout(function()    
    {    
       kill = true    
    }, 2000);    
}

Take a reference to the collider, then create a weld joint between it to the arrow. Also set the updateCallEnabled to false. So it not being rotated anymore. And kill the arrow after two second hit the target using setTimeout() function.

Done
Alright, it’s done. You can see the result and download the source code below:


download

27 December 2013

Finally I managed to built a small AIR app to solve the naming problem for TiledMapEditor TMX file. Seems that I’m underestimating myself, or probably I'm just too lazy. XD

tileNamer
TMX Tile Namer… Yeah, it doesn't sound right… I’m not even sure that the term “Namer” is exist on English dictionary… XD

This is just one button app. To use, click on the button, and a browse window will appear. Then you can search for the tile atlas XML file. Open the file, wait for couple of second, then a new XML file will be created on your desktop.
Additionally, you can simply drag and drop the XML file to the button, and it will automatically generate an output XML file on your desktop.

There are some limitations in this app:
The app only work if the tiles have uniform size and make sure there are no empty tiles in the tileset. See below:

sprites

Something like tileset below won’t work as you can see, there are three empty tiles. Because TiledMapEditor will treat empty space/tile/region as a single tile, while on the atlas XML file, there are no information for that empty tiles.

sprites - Copy

To solve the problem, you can add new tiles or duplicate some of the existing tiles, so there are no empty tiles. Not a resource wise for sure. But that’s the only solution for now.

Another limitation is that the app won’t write the tile name directly to the TMX file. So, to complete the process, open this app’s output XML file, and copy all the <tile> node inside the root node <tiles>.

tileNamer2

Open the TMX file with your code editor, then paste them inside the <tileset> node

tileNamer3

Still a little bit complicated, but surely less headache than giving name to each tiles one by one via TiledMapEditor. XD

Probably in the future, I’ll improve the app. But for now, it’s enough for me.
If you want to improve the app, then here it is the app source code.
The code is messy & not commented. I’ve warn you… XD
It is a Flash CS6 project, but you can simply copy-paste or move the Main.as class to your new pure AS3 project. Flash CS6 is just used to build the interface, well, in this case it’s just a background and a button

The AIR app is inside the bin folder, named TMXTileNamer.air. Since it built with AIR 3.9, then you’ll need latest AIR runtime on your machine to install & run this app.

Well, here it is the new sample project on my previous article, but now with few more tiles added.

26 December 2013

Alright, just want to share my experience when using Tiled Map Editor on Citrus Engine with Starling. Nothing too fancy here. Almost all of the process is pretty much same with my previous article.

citrus-tiled

Hell yeah, there are some additional workaround if you working with CE Starling mode. The very first different task is the tileset creation. Unlike the display list version which you only need a .PNG file for the tileset, on Starling version, you’ll need an texture atlas (PNG + XML file). There are some tools to generate texture atlas: Flash Pro CS6 or above, Texture Packer and ShoeBox. Well, there are probably another tools, but maybe I’m too lazy to do a google search. Smile with tongue out

Flash Pro is very expensive of course, but if you have the license, you can use it to create the tiles and export it to an atlas. Texture Packer is also the paid one, although they also have the lite version which will leave a watermark on your tileset. So better use the third tool: ShoeBox. A free AIR application that have several functions for processing game arts: creating spritesheet, tileset, generating PNG sequence from animation, etc. More than enough for me.

shoebox

As I said before, the tileset creation is different. You’ll need to export a separate bitmap file for each of the tiles from your graphic editor software to be processed on ShoeBox.

Using the same tileset from Kenney, and I pick a few tiles:

Tile starling citrus engine


6 tiles, and the other files are the atlas (PNG + XML) and TiledMapEditor TMX.

Now, we can create an atlas from these tiles. Simply select all of the 6 tiles, drag and drop it to Shoebox’s Sprite Sheet feature. And a new window will popped up:

Tile starling citrus engine

Alright, the tricky part starts from here. We need to make some adjustment, so we can use this tileset properly, because of this issue. As you can read on that forum thread, there will be some kind of transparent lines between the adjacent tiles when the camera moving. It’s look like the tiles aren’t attached to each other correctly.

Starling tiled map citrus engine

You can found someone else already asked about this issue on Starling or Citrus Engine forum. And also, on the Starling wiki already mentioned about this. Well, all of them already pointing out a proven solution: Add some extrude to the tilemap. Extrude is simply expanding the edges of the tiles by specified pixel size. How this option can solve the problem? Well, let’s just continue this article.

Now click the Settings button.  Another window will appear.

starling tiled citrus engine

First things first, make sure you select Starling, Sparrow on the Template dropdown menu.
“Tex Extrude Size”, well, that’s we’re looking for. Let’s change the value to 1. Problem solved? Not yet.
With Tex Extrude Size 1 and Tex Padding 1, we’ll get these tileset:

starling tiled citrus engine

Extrude working correctly, it expand the edges by one pixel. And the padding as well, it separate each tiles by one pixel. But as you can see, the adjacent tiles shared the same expanded pixel. The most noticeable are between grey tiles and brown tiles. Their expanded pixel is filled with grey color only. It’s definitely wrong.

The solution is just simply increase Tex Padding value. Ideally, it’s 2 times larger than the extrude value. So if the extrude size is 1 then the padding should be 2, and so on.
This is what we’ll get if using extrude 1 & padding 2:

Starling tiled citrus engine

With 2 pixel spacing between tiles, each tiles have one pixel extra on its edges. Now this is correct.

Tile’s spacing problem fixed. But before hit the shinny blue Save button, take a screenshoot/print screen your Sprite Sheet window. Make sure the tile’s label is readable. Paste it to paint, or other image editing tools, and save it.
Don’t ask why, I’ll explain it later.

starling tiled map

Alright you can hit the save button. Two new files will be created, a .png file and .xml. The xml file holds each tiles information, such as its name, coordinate, etc. While the png file is the tiles merged into one image file.

Now open the TiledMapEditor, create a new map with 70x70 px tile size since our tiles is also 70 px sized. Create new tileset, and use the png file that already generated before.

starling tiled citrus engine

But for the tile width and height, we set it to 71 px instead of the actual size (70 px), because we already add one extra pixel for each tiles using the extrude option.

Also for the spacing, set it to 1. Don’t know why it’s not using the same value as Tex Padding value on Shoebox, which we set it to 2. But I also don’t know why it’s work for me. So if the created tileset is separated correctly on TiledMapEditor’s tileset panel, then it’s mean that you’re set the spacing correctly. lol

On the tileset panel, right click one of the available tile, then select ‘Tile Properties’. A window will appear. We’ll give a name property to each tiles in the TiledMapEditor according to the already created tileset.

Now, open the previously taken screenshot. Using that screenshot as guide, then insert the corresponding name to all tiles.

starling tiled map citrus

Dafuq?

Yep, you’ll need to insert the name one by one. Clearly a tedious process, especially for a larger tileset with lot of tiles. Not to mention that you’ll need to re-adding the name property if you make some changes on the tileset. XD

I’ve no other solution for now. But if you have some free times, then you can create a tiny AIR tools to read the SubTexture’s name property on the tileset’s XML file and then write it to the TMX file. Both of the files are based on XML, so I’m definitely sure it’s doable with AS3. But still beyond my knowledge. XD 
You can take a look at my app here: TMX Tile Namer

Alright, because we only have 6 tiles, so it should be done just in a few minutes. Now you can start drawing your map and adding citrus objects just like on my previous article.

starling tiled citrus

The picture above shows how the extrude work. As you can see there are extra pixel on the edge of the tile. With these extra pixel, then surely there will be no more problem with transparent lines between tiles as I mentioned before. Because now it closed by that extra pixel.

Done?
If yes, then open your Flash Develop, or your own preferred IDE. Set up a Starling Citrus Engine project. Then create a state for the game screen.
I won’t explain that here. So if you’re new to Citrus Engine, then you’d better to find some basic tutorial.

The first things to do is embed the atlas files (XML & PNG), also the TMX file.

[Embed(source="../assets/bitmap/tiles/Tileset.tmx",mimeType="application/octet-stream")]   
private const tileMap:Class;    
         
[Embed(source="../assets/bitmap/tiles/sprites.xml",mimeType="application/octet-stream")]    
private const tileMapXML:Class;    
        
[Embed(source="../assets/bitmap/tiles/sprites.png")]    
private const tileMapImage:Class;


On the initialize method, under the box2d object initialization, put the code to parse the tileset.

var mapAtlas:TextureAtlas = new TextureAtlas(Texture.fromBitmap(new tileMapImage()), XML(new tileMapXML()));     
ObjectMakerStarling.FromTiledMap(XML(new tileMap()), mapAtlas);


As you can see, we create a TextureAtlas object for the map before inserting it to the parser. Using the embedded PNG and XML file.
And since we’re working using Starling, so we using ObjectMakerStarling utility class. And then call the FromTiledMap() method. It accept three parameters. The first one is the the TMX file. Since it need to be an XML object, so we cast it to an XML.
The second one is the atlas. Simply insert the mapAtlas object we’ve already created before. And the third one isn’t necessary.

Don’t compile the game yet, as I’m sure it will throw lot of  errors. It because the tiles name on the XML and TMX isn’t same.

To correct this, we need to make some edits on the XML file. It just simply remove the extension on the SubTexture name property. You can remove it manually one by one, or using search & replace function on your IDE.

starling tiled citrus

Now compile the game, it should be running perfectly, and you’ll see your created level.

Game Objects?
Starting from the hero, using the character PNG sequence form the same art package as the tileset. Make sure it’s facing right direction. And give it CitrusEngine’s default animation name (idle, walk, jump, duck, hurt).

Using the Shoebox’s Sprite Sheet function to generate a Texture Atlas. Pretty much same as we generate the tileset. But for this one, we set the Tex Extrude Size and Tex Padding to 0, as we don’t need these options.

starling tiled citrus engine

After that, you can create a Hero object on the TiledMapEditor. Give it “hero” name, and set some properties if necessary. But unlike on the previous article, the view property need to set via code, not inside TiledMapEditor.

So, go back to the code editor. Embed the hero’s PNG & XML files on your code.
[Embed(source="../assets/bitmap/hero/sprites.png")]   
private const heroImage:Class;    
         
[Embed(source="../assets/bitmap/hero/sprites.xml",mimeType="application/octet-stream")]    
private const heroXML:Class;


Then on intialize() method:
var heroAtlas:TextureAtlas = new TextureAtlas(Texture.fromBitmap(new heroImage()), XML(new heroXML()));   
var heroSequence:AnimationSequence = new AnimationSequence(heroAtlas, ["walk", "idle", "jump", "hurt"], "idle");    
            
var hero:Hero = getObjectByName("hero") as Hero;    
hero.view = heroSequence;


What we do is create a TextureAtlas object using the embedded PNG and XML file. Then create AnimationSequence object using that TextureAtlas.

We will using the AnimationSequence as the hero’s view. So grab the reference to the hero via getObjectByName() method. Then simply assign the AnimationSequence to its view property.

Do the same for other animated objects, i.e: the enemies.

For non animated objects like crate and coin, no need to create an atlas, as we can use just the PNG file. So embed the PNG file on your code, then to specify a view for the crate object is just something like this:
for (i = 0; i < getObjectsByType(Crate).length; i++)   
{    
      Crate(getObjectsByType(Crate)[i]).view = new Image(Texture.fromBitmap(new crateImage()));    
}


Draw Calls
The game should be running perfectly without any problem. But if you see on the Starling stats monitor at the top left of the screen, you’ll see that it used more than 50 draw calls.

StarlingTiled12

What is draw calls? While I’m not pretty sure about that, from what I know it’ll really give some effect to your game performance. The more draw calls the more chance that the game performance will be dropped, especially if you’re working for a mobile game.

So let’s reduce it by merge our asset into one big texture atlas. Collect the previously created atlases or art into one single folder. Then using the same Shoebox’s Sprite Sheet function, we create another texture atlas.

starling tiled map citrus engine

Open the created XML file on your code editor, the remove file extension on each SubTexture’s name property. We’ll use this name property to get specified texture from this merged atlas.

StarlingTiled14

Now, instead embedding different PNG files for different objects, we can just embed this previously created PNG file. So the embedding codes in the game state class should be look like this:
private var textureAtlas:TextureAtlas;   
        
[Embed(source="../assets/bitmap/atlas/sprites.png")]    
private var atlasImage:Class;    
        
[Embed(source="../assets/bitmap/atlas/sprites.xml",mimeType="application/octet-stream")]    
private var atlasXML:Class;    
        
[Embed(source="../assets/bitmap/tiles/Tileset.tmx",mimeType="application/octet-stream")]    
private const tileMap:Class;    
         
[Embed(source="../assets/bitmap/tiles/sprites.xml",mimeType="application/octet-stream")]    
private const tileMapXML:Class;    
        
[Embed(source="../assets/bitmap/hero/sprites.xml",mimeType="application/octet-stream")]    
private const heroXML:Class;    
        
[Embed(source="../assets/bitmap/enemy/slime/sprites.xml",mimeType="application/octet-stream")]    
private const slimeXML:Class;    
        
[Embed(source="../assets/bitmap/enemy/snail/sprites.xml",mimeType="application/octet-stream")]    
private const snailXML:Class;



We just embed one merged PNG file. No more embedding each different object’s PNG file.

So, to use it we need to create a TextureAtlas object.
textureAtlas = new TextureAtlas(Texture.fromBitmap(new atlasImage()), XML(new atlasXML()));

If this object already created, we can simply call the getTexture() function to gather the specified object’s atlas or image.
For the hero, now we do something like this to create the atlas:
var heroAtlas:TextureAtlas = new TextureAtlas(textureAtlas.getTexture("hero"), XML(new heroXML()));


And for non animated object as well:
Crate(getObjectsByType(Crate)[i]).view = new Image(textureAtlas.getTexture("box"));


Simply call getTexture() function from textureAtlas object, and insert specified name to its parameter.

Compile and run the game to see the difference…

StarlingTiled15

Yep, now it’s only have three draw calls. That’s a huge difference.

The End
Well, this is the end of the article
You can test the finished game, as well as the source code.

download

Shameless Promotions
Just in case you need some tilesets, game characters, and/or game interfacesNyah-Nyah

royalty free game tile set

royalty free game sprite sheet

royalty free game interface

Or go here to view the complete items.


Btw, why the heck the colors on some of the image on this article became washed out?