HaxeFlixel Tutorial – Loading TMX Data

Edit 2015-04-24: This tutorial has been revised completely to cater for multiple tile/object layers.

So far we have covered how to load CSV data and then parsing the loaded data. However, we assumed there’s only one layer; so if there is a player tile at (10,5), then there cannot be any ground tile behind it. And what if there’s an enemy that spawns on a specific grass tile? We would usually need layers. This is where Tiled Editor and the TMX file come in.

In Tiled, you can create multiple “tile” and “object” layers. You could have a map with the following setup:

  • tile layer for background (ground, river, etc.)
  • tile layer for foreground (walls, trees, etc.)
  • object layer for actors (player, enemies, treasure, etc.)

Before we proceed, let me share some nuggets of knowledge I gained while researching on how to parse TMX data:

  1. What you need to load TMX data
    • In order to load TMX data, you only need the TiledMap addon,  flixel.addons.editors.tiled.TiledMap .
    • The addon is a haxelib which needs to be enabled in the Project.xml file, like this:  <haxelib name="flixel-addons" />
  2. TMX layer data format
    • Getting the layer data is quite flimsy: if the TMX format is in CSV, then you need to access the data via “csvData” property. If the TMX format is Base64, you need to access the data via “tileArray” property. I couldn’t get XML data from the TMX file, and since FlxTilemap isn’t able to parse XML data anyway, we’re only left with two choices.
  3. Parsing TMX data
    • TiledMap only loads the TMX file’s data. You will have to parse the data yourself. TMX data loads two main parts of the file — the tileset list, and the layer list.
    • The tileset list contains all the tilesheet images that you used in the TMX map. In Tiled Editor, you can import multiple different spritesheets and use them in one project.
    • The layer list (if you saved the layer format as CSV) will contain an array of CSV data for each layer. This is just a more convenient way of saying the TMX file keeps multiple CSV data in one place.
  4. TMX loading/parsing limitations
    • This is very important when proceeding with parsing TMX data. I struggled for a long time on figuring out an easy way to do this, until I realised the following limitations.
    • HaxeFlixel does not have any function (as far as I know) that supports loading a tile map which uses multiple tilesheets. As such, each layer can only have ONE tilesheet associated with it.
    • Layers in the TMX file also do NOT store info on which tilesheet is being used. As a result, you need to add a custom property on each layer to explicitly store the name of the tilesheet you used for that layer.
    • In short, TiledMap only extracts most of the important info you need from the TMX file. It’s entirely up to you regarding how you’ll use the data to generate and render the tile map.

With the wisdom above, let us proceed.

Setup

First, let’s create a template HaxeFlixel project with an arbitrary name:

Next, let’s setup the necessary resources — we need a placeholder tilesheet. Let’s use this excellent sample from Sharm, “tiny 16 basic“. We’ll be using 4 images from there:

  • basictiles_2.png
  • characters_1.png
  • dead_1.png
  • things_0.png

Put the images in your project’s  /assets/images  folder.

TMX Data Setup

Now to create the TMX file. Here’s the bare minimum steps you’d usually have to go through to create a layered TMX file:

1) Create a new project.

tmx-tutorial-ss0

2) Add the image tilesheets (basictiles_2.png, characters_1.png, dead_1.png and things_0.png) to your project.

tmx-tutorial-ss1 tmx-tutorial-ss2 tmx-tutorial-ss3

3) For the purpose of demonstrating multiple tile and object layers, let’s create two tile layers and two object layers. In my example below, I renamed the layers to match the tilesheet image’s name which I’ll use for each layer.

Screen Shot 2015-04-24 at 11.36.15 AM

4) Add a custom property to the tile layers so that when we parse the data in HaxeFlixel later, we can know what tilesheet this layer is using.

tmx-tutorial-ss9

5) Do the same for the object layers.

tmx-tutorial-ss8

6) Now place the tiles in the tile layer as you like. In my example below, I tried to use all possible tiles from each layer to test if all of them would appear correctly:

Screen Shot 2015-04-24 at 11.12.09 AM

Screen Shot 2015-04-24 at 11.12.23 AM

7) Do the same for the object layers:

Screen Shot 2015-04-24 at 11.44.58 AM

Screen Shot 2015-04-24 at 11.46.33 AM

8) When I enable all the layers, I should be able to see all of them, like this:

Screen Shot 2015-04-24 at 11.45.26 AM

9) This step is optional. When you have specific object types in the object layer, such as “player”, “enemy”, “door” and “key”, you would normally do this — Select an arbitrary “player” object and add a custom property “type” to it, with the value “player”. We will use this value to parse it in TiledMap later. Without doing this, we won’t know how to identify different unique objects in the layer when we want to parse the data later. Repeat this step for other objects, such as enemies (“type” = “enemy”).

tmx-tutorial-ss7

10) Save the file as something easy to remember, e.g. “my-map.tmx” Put the TMX file in the /assets/data  folder. You’re now ready to load and parse the map data in HaxeFlixel!

Code

Now let’s get straight to the code:

Now if you test the game with lime test neko  …

Screen Shot 2015-04-24 at 11.56.20 AM

Oops, I forgot to set the screen resolution, but let’s assume you fixed that (change the gameWidth  and gameHeight  values in Main.hx).

Anyway, the game renders the two tile layers correctly! Now you know how to load multiple layers in your tilemap. Now let’s load the game objects:

EDIT: Thanks to Keith for the info — If you’re familiar with some other languages (C++, C#, etc.), you probably have this habit of ending every switch case with a break , like I do.

However, in Haxe, switch cases do NOT fall through, as stated on the syntax page. In fact, if you add breaks in your switch case, it will end up exiting the while-loop or for-loop outside of the switch block.

… And now, we can see the objects on the map as well:

Screen Shot 2015-04-24 at 12.03.46 PM

But wait, we’re not quite done yet — Notice that the placement of the objects in the layer is a little off (the y-position is lower by one tile than it should be). Thanks to Rafael J in the comment for fix:

And now the positions are all correct!

Screen Shot 2015-04-24 at 12.16.58 PM

The code above isn’t complete — we didn’t cover customising tile property, player/enemy logic, etc.. But anyway this concludes the tutorial. Thank you for reading. :)

15 thoughts on “HaxeFlixel Tutorial – Loading TMX Data

  1. thronecode says:

    Thank you very much for this amazing tutorial, it helped me a lot!

    However I have doubts about layer transparency, has any of you had problems with an upper layer having a black background?

    I’m the whole day trying to figure out a way to fix this, I’d appreciate any help!

    Thanks again!

    Cheers!

    • WY Leong says:

      Hi there thronecode,

      I haven’t used HaxeFlixel for a while, I don’t know if this is a framework-specific issue or not. But my first guess is — is your image transparent PNG?

      • thronecode says:

        Hey WY, thanks for the frightfully quick answer!
        Well, I know this is an old post, but the content I found here was the most well explained and well documented on the internet.

        I might have made some confusion with my code. It was not a problem with Your tutorial, HaxeFlixel, Tile or Haxe either.

        When I reproduce the error, I’ll post news about it.

        Thanks WY, you’re awesome :)

        • WY Leong says:

          Hi thronecode, you’re welcome! I just happened to login at the time of your writing. 😛

          Anyway, hope you got the error sorted out. Good luck on whatever it is you’re working on! 😀

  2. Keith Weatherby II says:

    I don’t know if you’re still looking at these comments but for anyone who looks here in the future, I found a trick that can make finding the correct tileset easier and not have to use a loop.

    Note your code here:
    // Note: “0” is empty tile, so default to a non-empty “1” value.
    var tileGID:Int = 1;

    for (tileset in tiledLevel.tilesets)
    {
    // We need to search the tileset’s firstGID — to do that,
    // we compare the tilesheet paths. If it matches, we
    // extract the firstGID value.
    var tilesheetPath:Path = new Path(tileset.imageSource);
    var thisTilesheetName = tilesheetPath.file + “.” + tilesheetPath.ext;
    if (thisTilesheetName == tilesheetName)
    {
    tileGID = tileset.firstGID;
    }
    }

    Well if you go into your map file in Tiled and rename the tileset to the name you have stored as your layer property, since tilesets are maps using the name as a key, you can simply use the tileset name as the key. Like so:

    // if we make sure the tileset name is the same as the
    // one we put in the layer property, then you can simply
    // use the name as the key into the tileset map(dictionary)
    var tileset = tiledLevel.tilesets[ tilesheetName ];
    if ( tileset != null ) // check for null because it’s possible you could use the wrong name.
    {
    tileGID = tileset.firstGID;
    }

    So now you don’t need to waste time and screen space with loops. You just need to name your tileset the same that you name the layer property. In my case I did the full filename like blocks.png — so that’s what I did.

    • WY Leong says:

      Hi Keith! Thank you so much for the alternate way to process tilesets. I’m sure people will find your method more convenient. 😀

  3. Rafael J says:

    Hi,

    Objects in tiled are aligned bottom-left (top-left in flixel):

    Add these lines after ” var objY:Int = object.y;” to solve:

    if (object.gid != -1)
    objY -= group.map.getGidOwner(object.gid).tileHeight;

    Rafael J.
    (from Brazil)

    • WY Leong says:

      Hi Rafael,

      Glad the tutorials helped you. I’m a beginner myself, so I can only write about things I learned so far. :)

      And thanks for the info on the code! I’ll try it out and edit the post soon. 😀

      EDIT: I expanded on the code in the post above and realised that the whole tutorial doesn’t work when you have more tile/object layers. I’ll rewrite the entire tutorial once I figure everything out :)

  4. Rafael J says:

    Hi,

    I’m learning haxeflixel and your tutorial is perfect for my needs!

    Please, post more basics tutos like this.

    I’m choosen between stencyl and haxeflixel. It’s hard to find basics tutos about haxeflixel

    Thanks!
    (Rafael J. from Brazil)

  5. WY Leong says:

    Hi Keith!

    Thanks for the heads up. I didn’t know it works this way. I’ll edit the post with some additional info regarding this, after I experiment with breaks in switch/for loops.

    I can’t remember which of my previous posts had this mistake too, but I’ll keep in mind for future posts. Thanks again!

  6. Keith Weatherby II says:

    In HAXE switch cases don’t fall through, so a break isn’t supported. In fact break will literally break out of the for loop. So you want to remove the break statements from the switch. It took me a day to figure out what was going on, because I’m from a c/c++ background and the break; looked correct to me too. Otherwise good work!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">