Retrieving Tile Information at Runtime with Tiled2Unity

by Seanba on September 20, 2015

If you are building a strategy or RPG style game then there’s a strong chance that you need to get at specific information about each tile placed in the world. Unlike platformers, where tiles are decoration, each tile is an important part of your game logic. In this post I’ll show you two techniques to easily add such support to your Tiled2Unity projects.

Which approach you take will depend on the specific needs of your game measured against performance and memory usage. In my opinion, a good rule of thumb is to ask if your game is more like Advance Wars and Fire Emblem (use GameObject approach) or more like Final Fantasy and Dragon Warrior (use PolygonCollider2D approach).

Tiled Automapping Feature

Both approaches make use of the powerful, yet regrettably arcane, automapping capabilities of Tiled. I recommend boning up on this feature as a prerequisite, and not just for this exercise. You will likely use this feature extensively once you understand how to create automapping rules for your Tiled maps.

Note: If you’re having a hard time figuring out how to use automapping, I found this video to be helpful in making sense of it all. It’s 10 minutes well spent.

Example Project Files

Tiled map files and C# source used in these examples is available on GitHub as a Unity project that you can run and experiment with yourself.

TileObject Approach (Strategy Games)

Turn-based strategy and board game style games typically require each tile on a map to be a central part of the gaming logic. Each tile instance, although similar to others of the same “type” has to know where it is on the board as well as manage other game state (say, which units are standing on it, or how it influences other tiles or sprites around it). This is best handled in Unity by having each separate tile be associated with a GameObject made up of Components unique to the game you are making.

To achieve this we’ll have our Tiled map automatically generate Tile Objects that, when imported, are consumed by a custom importer script. During this custom import step we will attach GameObjects to our map prefab that is simply placed into a scene to do it’s job.

For this example I’ll use Fire Emblem as inspiration. Here’s the map from the first chapter of that game in Tiled:

Fire Emblem (GBA)

For now, I’ll focus on the trees. What we want to do in Tiled is set up a rule that will place an object with custom properties on it in an output layer every time it sees a tree tile as input:

Rule for tree file

Working with automapping rules in Tiled at first can seem tricky. See fe-rules.tmx in the example files to see how I’m setting up rules for the Fire Emblem example.

Applying that rule you can see how a Tiled Object was placed upon every tree tile in the map:

Tiled Objects added to map

Once our automapping rule is created we see that objects are automatically added to our map.

Upon export into our Unity project, those objects are added to the map prefab as Unity GameObjects. There isn’t much to them originally besides a BoxCollider2D so that’s where our custom import script will come in.

[Tiled2Unity.CustomTiledImporter]
public class CustomImporter_StrategyTiles : Tiled2Unity.ICustomTiledImporter
{

    public void HandleCustomProperties(GameObject gameObject,
        IDictionary<string, string> customProperties)
    {
        if (customProperties.ContainsKey("Terrain"))
        {
            // Add the terrain tile game object
            StrategyTile tile = gameObject.AddComponent<StrategyTile>();
            tile.TileType = customProperties["Terrain"];
            tile.TileNote = customProperties["Note"];
        }
    }

    public void CustomizePrefab(GameObject prefab)
    {
        // Do nothing
    }
}

The CustomImporter_StrategyTiles.HandleCustomProperties method is invoked for every Tiled Object in our map file. As you can see from the code above we are looking for the custom properties we’ve added to our Tiled map and, once found, we shove them into a custom component to be used by our game.

After filling out our automapping rules for all other tile types (mountains, water, grass, etc..) and re-exporting we now have a prefab, fully constructed by Tiled2Unity, that has unique data associated with every tile. In the example provided, I simply do a raycast off of mouse button click to find out which tile we’ve “selected”. I also keep a count of how many times you’ve clicked on that tile to demonstrate that game state is kept on a per-tile basis.

Fire Emblem tiles in Unity

In the example demo, you can click on any tile and see what game state data is associated with it. Here, the game state is simply the number of times each tile has been selected.

Word of warning: Keep in mind that in this example we are (automatically) creating an object for every single tile placed in Tiled. This works well for games with smaller maps where you’ll have on the order of several hundred such objects. However, for larger maps the number of game objects in your scene could easily affect memory and performance. Remember that a 256×256 map will have 65,536 such objects which is likely too much complexity for Unity projects.

PolygonCollider2D Approach (RPG Games)

In RPG style games we are often more concerned by the “type” of tile our player is standing on as opposed to the exact tile instance. (In other words, we want to know if the player is in a forest, but we don’t care about a specific tree.)

This is a great job for the polygon colliders that Tiled2Unity creates from the Tile Collision Editor in Tiled. However, polygon colliders are created on a per-layer basis and it’s a total pain in the ass to have to manage separate layers for each type of tile we may have in our game.

Again, this is where automapping can help us and in this case the mapping rules are dead simple. All we need to do is take every tile from a single input layer and output the exact same tile to a particular output layer — one for each type of tile.

Working layer

Our working layer is the only layer we need to manipulate in Tiled. However, it is exported as one big collision. We can’t tell if we collide against water or mountain or grass tiles.

 

Output layers

By setting up rules to automatically create output layers for each tile type we can export the map with separate colliders for each type of tile in our game.

Setting up our rules this way allows us to work in only one layer and have all the output layers created for us automatically. The example contains part of the Dragon Warrior overworld (Charlock Island) with the polygon colliders set up for each tile type. We just do a raycast from the mouse position to see what kind of tile we selected.

Dragon Warrior example

In the Dragon Warrior example we can select which type of tile we are interested in.

You can see how this would work for a proper RPG style game, giving you the ability to spawn monsters that belong to a particular type of terrain. You get the added bonus of having collision detection for parts of the world you want to keep your character out of. (Also note we don’t need custom importer scripts for this example.)

Can’t There Be An Easier Way?

All things considered? I don’t think so. I often get requests from developers that “just want to get a tile” at runtime thinking that data should be right there waiting for us. I see two problems with that:

  1. Maps grow with quadratic complexity. One of the chief benefits of Tiled2Unity is the simplicity of minimal meshes and polygon collider objects that are made to work with Unity.  Managing objects on a per-tile basis, for all Tiled2Unity users, would undo that.
  2. What would per-Tile information look like anyhow? In my mind, there is no way to make a general, one-size-fits-all offering for this. All data in Tiled is text but when we consume it in our game it must be in a format that makes sense for our specific application.

Having said that, with some clever use of features already available to us and maybe a little tool-side scripting you should be able to make Tiled and Tiled2Unity work for you in ways that are unique to your game development needs.

 

{ 14 comments… read them below or add one }

Maenor October 9, 2015 at 10:48 pm

Wow! Thanks man!! *-* I just can’t understand how can there be so amazing people on this world!! xO Taking the time to make all of this … is just … freaking awesome!! … And then set it free?! xP
I was about to mail for the same topic (On which i was only to ask for you guide and scripting logic! xP)
Thanks again!! :’)

Maenor October 9, 2015 at 11:32 pm

By the way! ^^
The project on GitHub … i cannot get it to work! .-. It gave me tons of errors when i opened the scene.

Maenor October 10, 2015 at 10:16 am

I have both Unity 4.6.7 and 5.1.1 and none of them seems to be able of open the project …at least i tried to open the scene on 4.6.7 (Yesterday) and i got some critical errors about materials, textures and other kind of stuff … sadly i didn’t take a pic … sorry.
Which version is the one that you used on how did you open it?

Seanba October 11, 2015 at 3:53 pm

I just downloaded the example clean and it worked. I would expect it to run on any Unity 5.x (and probably 4.6) install without any issue. If I had something more specific to debug I could probably help or fix.

bagellad November 4, 2015 at 9:12 pm

I had the same issue with the sample files, but once i upgraded my unity it went away.

It might be that I am home with the flu but for the life of me I can’t figure out how to spawn a custom object, like say a treasure chest from tiled and then have it work within unity. I was trying to add another

“if (customProperties.ContainsKey(“Terrain”))” but looking for another property like “Test” just after the other if statement but I cannot get it to work, but it is getting my updated map because i can see the geography change…

I also can’t seem to get any debug.log to output anything within the public class CustomImporter_StrategyTiles. To help with my debugging.. any suggestions?

bagellad November 4, 2015 at 9:15 pm

Oh and i like your program!

daniel November 6, 2015 at 9:22 am

helo! can i turn off the boxcollider2d spawning? btw u are great!

Seanba sez: Yes, select the layer in Tiled and add a custom property named unity:ignore and set the value to collision. That will keep any colliders from being generated on that specific layer.

daniel November 7, 2015 at 7:47 am

ty for answer. It is not works on object layer :c my main problem is the animated tiles had poor performance. i made a customTiledImport for handle animations. It is works well, but after every BIG ASS EXPORT i have to delete 2d box collider. I have not found the instantiation script and i couldnt destroy the boxcollider in the customtiledimport script.
sry for my terrible english and thx any advice.

Seanba sez: Daniel, can you export your Unity project and email it to me? I can find some time this weekend to check it out.

Ken November 8, 2015 at 1:13 am

Just wanted to say thanks for this! I’m pretty new to game development and Unity and wanted to see how far I could get making a game similar to FE. I already coded up some game logic in C++ (used SDL) that I translated to C# (for Unity) so I could take advantage of Tiled2Unity and other Unity perks. Since I wanted to reuse as much code as possible (and I had already handled the representation Tiles in a different way), the PolygonCollider2D method was just what I needed to quickly get and bridge the tile types into my game logic.

Since the GBA FE games are pretty popular, I already had a few completed maps at my disposal. It felt easier to just create a layer for each tile type in Tiled and then “color in” the relevant tiles on the base layer in each layer with collision tiles since there were many different tile images that are of the same type (and making rules all of the tiles seemed like it would take a lot of time if I understand the process correctly). Also, after importing into unity with Tiled2Unity, instead of separating the tile type-collisions into different layers, I put them all on the same layer and used the raycast technique to reference the collisions’ parents gameObject names instead of the layer names.

Thanks again!

Angel Biedma December 31, 2015 at 11:18 am

Thanks for your tutorial but I am having some issues. In my case, in StrategyTile class I’m storing all tile attributes into a public member Dictionary TileProperties, I modified properly CustomTiledImporter to add each custom property to TileProperties dictionary and print a log message.
Log message is printed but then in the inspector the dictionary appears empty and i don’t know why.

I’m a bit newbie with Unity but I am a medium skilled programmer in Java and I know C# aswell.

Merry Christmas.

Feliza January 8, 2016 at 3:52 pm

Hello, i got some questions concerning the polygoncollider2d approach.
How do i know what kind of tile my raycast hit, is it the name of the layer or something?
Basically i have a collider on each and every object, right? Doesnt that mean that i have to select which collider one can walk through and which not for every group of objects in unity for every map,which is a lot of work?

Thanks for answering my questions in advance.

Best wishes

Feliza

Mystic March 9, 2016 at 12:22 pm

Hey!

I think ModelImporterNormals and ModelImporterTangents are deprecated now, and my version of Unity won’t even compile this example because of it.

Seanba sez: Hey! (I mean, hi Mystic). What version of Unity are you using? And what is the exact compile error you are getting? (Email me.)

FunToBuild March 12, 2016 at 10:03 pm

That auto-map is super useful.. not only for specific in-game objects (which took about 20 minutes to figure out what I needed to do) but things like auto-inserting “coastline” tiles terrain based on a left-water and a right-land (for example). Thanks!

rraallvv September 23, 2016 at 7:26 am

Hi there,

Does anyone know about a good video tutorial on how to do this?

I’m new to Tiled and Tiled2Unity, and can’t find too much information on how this is done, I tried following the tutorial on this page but can’t figure out how things are related to each other. For instance what is the TSX file in the repository? why are the custom properties grayed out in the sample maps? Do I need to write the custom script? where do I need to put it?

Any help/comment is appreciated.

Leave a Comment

Previous post:

Next post: