There are a ton of resources available that show the end result of tile-based games. Fans, hobbyists etc, painstakingly capture entire dungeons, shops, towns and world maps etc. from their favorite games. The TileMapper project is a tool created using Unity which allows you to easily extract the unique tiles from a tile map (for educational purposes of course). It has a variety of features to make this process easy and even includes a feature to help you recreate the map using the newly captured tiles.
I have already created the full project and it is available here. Download and unzip the project. I created it in Unity 5.5.0f3 – you will need to open it with a compatible version. Feel free to poke around and see how the scene, prefabs, etc are setup. However, if you run the scene now, all you will see is a blank white screen. This is a tool that needs “something” to work off of. You’ll need to gather some resources to work with.
Since I have been playing around with creating a Final Fantasy style RPG, I primarily worked with the “world map” and a town called “Cornelia” from Final Fantasy 1 while creating this tool and its accompanying documentation. The Nintendo Entertainment System (NES) versions were easier to work with, but the Game Boy Advance (GBA) versions were much prettier.
Of course the tool will work with any tile map you like, and there is nothing to force you to work with the ones I chose – there are a ton on Spriters Resource. I even used a few comps from Pokemon to experiment with assets that included different tile sizes and spacing between the tiles.
Pokemon sprite sheets:
- Pokemon FireRed / LeafGreen (GBA), some building sprites
- Pokemon Black / White (DS), 1st Gen Pokemon sprites from the front
Regardless of what images you choose to use, make sure you grab something and add it to your project. Some of the texture import settings will need to be configured as follows:
- Under the Advanced import settings, make sure that “Read/Write Enabled” is toggled to “ON” – this will allow us to clone and read the pixels from the image.
- Set the “Filter Mode” to “Point (no filter)” – this makes sure you see all of the pixels nice and crisp instead of letting anti-aliasing attempt to blur them all together.
- Set the “Max Size” all the way up – “8192” just to be sure that Unity isn’t trying to resize the asset for you.
- Set the “Compression” to “None”
First things first. Before we can cut up a tile-map into its unique tiles, we need a way to load and view a base image to work from. Open the TileMapper scene. Even though this is a tool designed to work in the Editor, I actually designed it to work with the Play mode active so that we could make use of things like Canvas UI and the input event systems that go with it.
Go ahead and run the scene. I’ll assume you already imported some resources to work from. While the scene is running, look in the Hierarchy pane and select the Image Previewer object. Now find the Image Previewer component in the Inspector pane.
Assign one of your reference images to the “Original Texture” field. Then click the “Load” button at the bottom of the component. You should notice your image appears in the Game screen. The Work Area’s default Width and Height will also have been updated to match the dimensions of the image. Assuming your image is large enough, you should be able to click and drag on the Game screen to pan around and see different areas of your image.
In this case, I have loaded the Cornelia GBA asset. Viewed from the Scene pane, you can tell that there is a bunch of extra content, such as labels, the shop interiors, and cuts of the river area at each frame of animation. I don’t actually want to work with most of this at the moment, so I will use a feature of the Image Previewer to setup a “work area” as follows:
- x: 20
- y: 594
- width: 704
- height: 496
The image below shows a preview of the Cornelia tile map, but I have marked the “work area” which I specified with a red border, and shaded the rest of the image. In the editor, you can use the game screen to pan around and it will appear as if we have cropped the asset so that only this small region remains.
If you hover your mouse over the label of a field you will see sideways arrows appear on the mouse pointer’s tip. This indicates that you can click and drag to the left or right to modify the value in the field, almost as if it were a slider. This lets you quickly approximate your work area without a bunch of manual typing.
The values in the fields will automatically clamp to values based on the size of the image. If you input large offsets in the work area, the width and height will automatically shrink so the values remain valid.
I set default values on the Image Previewer prefab and its components so that it would look good with most of the assets I was working with. There are a few ways you can zoom in or out according to your own preference:
- You can adjust the Scale slider in the upper right corner of the Game screen.
- You can use the Scene screen to zoom or pan around and even see the whole image at once if it helps you.
- You can modify the Canvas Scaler component. The default values I used are 240 x 160 which approximates the way the tiles might look when played on a Game Boy Advance.
The values I chose for the work area weren’t chosen at random. I actually made sure to use very specific values so that the work area snapped to tile boundaries. In order to determine the ideal settings I used a component called Checkerboard. You can find this component on the Image Previewer GameObject. It will be disabled by default in my project because it is an optional feature that you may not always want to use.
Go ahead and enable the Checkerboard component now so you can see what it does. The image below shows the Checkerboard overlaid on top of the tile map I am working with. I knew I found the correct offset when everything “fit” such as the corner piece of the wall, the centers of the path, and even the base of the fountain.
You can tap the value area of the “Checkerboard RT” field on the Checkerboard component in the inspector pane. This will automatically expand the object heirarchy and flash a highlight of the matching GameObject reference in the Hierarchy pane. If you select the indicated target object, you can find a Image component. Here you can adjust the tint or alpha used on the checkerboard to your preference. You can also swap Grid_A for Grid_B to flip which squares are opaque vs transparent.
In my first example with the Cornelia town map, the grid size already happened to be the correct size. There are of course different assets that will require different tile sizes, and occasionally even tile spacing. Both of the Pokemon resources I linked to earlier will require spacing and one has large tiles.
The sprites with the pokemon fronts are 96 x 96 pixels and have 7 pixels of spacing between each row. The sprites of the pokemon buildings are 16 x 16 pixels but have 1 pixel of spacing on the rows and columns.
The Grid component is found on the “Image Previewer” GameObject. You can modify its “size” or “spacing” fields as you like. The other components which rely on the grid will automatically adjust themselves, although the Checkerboard component does not currently support tile spacing.
The Mapper component is the first tool which actually extracts tiles for you. It is designed to grab the “background” tiles – the ones that don’t have anything overlaid on top. For example, if it is a simple grass, wall, or path tile and a bush or tree doesn’t happen to cover any of it.
Using the Game screen, you can use the mouse to click on any tile you want to capture. Assuming your grid and work area settings line up with the tiles correctly you will see a tile “marker” appear directly over the tile you clicked. In the image below, I clicked on a wall tile with a window:
The Mapper component is located on the Image Previewer GameObject. Find the component in the Inspector pane and you can see the “Pos” (position) which is the row and column index of the tile you clicked. You can manually enter values too. When you are ready, click the “Capture” button:
A new screen appears which shows a closeup of the area you selected. For now, you can try entering a name into the text field and then click the Save button. Your saved asset will appear in the Tiles folder of the Project pane. If you selected the wrong tile on accident you can always click Cancel to return to the previous screen.
After capturing a tile using the Mapper, its pixels on the reference texture turn black. In fact, if there are any duplicates of the tile, they will also have turned black. This is due to the progress marker. The general idea is that you want to wipe out the entire image and then you will know you have captured it all. It also helps you to figure out where other unique tiles exist since they are the only ones remaining.
Some of the larger or more detailed maps may require you to capture a large number of tiles. If you should mess something up or accidentally stop playing the scene you might be afraid you have lost all of your progress. However, there is another feature of the Progress Marker which allows you to quickly return to where you left off. First you will need to (at least temporarily) modify the texture import settings of the captured tiles like you did for your other resources. At a minimum make sure that the “Read / Write Enabled” is “true” and the “Compression” is set to “None”.
Next drag all of the tiles you’ve captured (located in the Tiles folder on the Project pane) to the “Samples” array field of the Progress Marker component. This component is also located on the Image Previewer GameObject. Now press the “Remove Samples” button, and all of the blacked out tiles will appear as they had the first time around.
Sometimes tiles might be reused across more than one map. Using the samples feature, you can quickly black out the new map and see if there are any new tiles remaining or not.
Don’t worry about the texture preview getting blacked out – it is painting over a copy of the original texture.
If you don’t want the progress to be marked like this, you can also disable the component. The assets will still be saved.
Look on the Image Previewer GameObject and disable the Mapper component in the Inspector pane. Next enable the Overlay Mapper. This alternate mapper is designed to help capture tiles that should have transparency in them and which appear on top of other tiles. If you can find the same transparent foreground tile over two different background tiles, then those differences can be automatically removed for you.
Just like with the first Mapper, this mapper also allows you to click on the camera screen to place a marker. However, this mapper uses two different markers. After I click the first location, I look in the inspector and copy the values from “Pos” to the “Pos 2” field – this causes the Red Marker to move. Then I click somewhere else, to move the first green marker to another new location.
In the image below I have placed a green marker over the top of a tree which appears in front of the grass, and the other marker over the top of a tree which appears in front of a wall.
After clicking the “Capture” button that appears on the “Overlay Mapper” editor, the painter window will appear just as it had before, but this time the background will have already been masked out for you, leaving only the tree top. Don’t worry about the ugly magenta background – it wont be saved as part of the captured tile, those pixels will be clear.
You’ve seen the painter a few times now – it appears after capturing a tile and gives you a chance to name the tile before saving it to disk. However, it has another very important job. Sometimes, it is hard to get different enough backgrounds for the foreground tiles to get a perfect auto-mask. Or there may not be a different background at all. In these cases you might need to manually paint out some of the pixels. Rather than having to export the tile and clean it up in something like Photoshop, this little editor will allow you to finish the job right here.
In the image below, I used the Overlay Mapper to select two bushes which appeared on opposite sides of a path from each other.
The auto-mask worked pretty well, but left a few pixels to be cleaned up manually. You can use the mouse to click and drag over the pixels that need to be erased. If you accidentally erase too much, you can fix it by holding shift while painting and the pixels will be repainted just as they were before.
Below I have the bush and its shadow with the stray bits of extra grass removed.
If all you wanted was to extract tiles so that you could paint your own new maps, you might be done with this tool. However, if you wanted a way to help recreate the map using the newly extracted tiles, there is one last component which can help. The Mapper History component sits at the bottom of the list of components on the Image Previewer Game Object. It has been quietly listening and waiting all along. Once you have completed emptying a map, simply type in a “File Name” and click the “Save” button.
A new text file will have been added to the root of the assets folder according to the name you provided. It is filled with JSON which should be relatively easy to apply to something else in the future. I dont know how you will wish to store your level as an asset, so I chose this generic JSON file so it could be as simple and reusable as possible.
If you crack open the contents of the file you should see that the data is formatted like a dictionary. There is an entry for:
The “colCount” and “rowCount” are hopefully intuitive enough – they indicate how many columns and rows fit in the resulting map based on the “Grid” tile size and the “ImagePreviewer” work area you have specified.
The “textureNames” holds an array of the names of the tiles you saved. This way you can potentially load those textures again as a resource to reuse later when you create the system that works with a tile set.
The “mapping” is a bit less intuitive. It is an array of indexes. Its length is equal to the row count multiplied by the column count. In otherwords it is a “flattened” array which holds the same data a 2D array of the map would hold.
There is a simple formula to help you get a tile at whichever coordinate you want:
int tileIndex = yPos * colCount + xPos;
What this code shows is that the index of a tile (in the “flattened” array) is equal to the y-coordinate multiplied by the column count plus the x-coordinate.
The value you would find inside the mapping array at the tileIndex is yet another index. The index value held at that spot in the array is the index of a texture name. Even though this causes the output data to be a little less obvious, it has the benefit of requiring a significantly smaller amount of text, and thus will be a smaller file size and will occupy less memory.
If you change the grid’s values or image previewer’s work area after you have already captured tiles, then the data held by the Mapper History will be incorrect. You can always quickly recreate the capture session by using the samples feature of the progress marker to complete the job all at once. Now when you save the resulting history it will all have been recorded using the same settings and will produce a better result.
In this lesson I introduced a tool created in Unity which helps extract unique tiles from tile maps and even helps in putting them back together again. I covered each of the important components that play a part in this process and gave some plenty of tips for potential workflows you might encounter.
If you have any questions, feel free to leave a comment below.
6 thoughts on “Tile Mapper”
I never thought about writing a tool to extract tile sheets from tile maps. Great idea and very inspiring to cobble something playable together in Swift, too 🙂
Hi Jon. I’ve been following you for a while 🙂 you make the best coding tutorials that I have ever found.
I’d really like to know your approach on mecanim. Mecanim is one of those things that have a million tutorials…but they are all messy, redundant and would be a nightmare on a character with lots of animations
Thanks, thats very kind of you to say. I think Mecanim is an interesting tool with a lot of potential, but to be honest I haven’t used it as much as I would like to. If you’ve already gone over those other tutorials (including Unity’s such as their rogue-like tutorial https://unity3d.com/learn/tutorials/projects/2d-roguelike-tutorial) then I won’t have much to add at the moment. I’ll try to keep it in mind for a future project so that I can pick something that benefits from it though.
Hmm…well, explaining it a bit better, it’s not along the lines of “I can’t get it to work”, its more like “not neat and tidy enough”. Everytime I have to add a new animation, I have to: 1-add on the Animator plus all the ins and outs of this new state, 2- add one more line to the animations enum, 3- another Case in the switch, 4- another method plus revising the new ins and outs of this animation state(additional work if other scripts can change the state).
I was rereading some of your stuff on the tactics tutorial and that project’s StateMachine gave me some ideas, do you think it would work as an animation controller or is it too heavy for that?
You’re definitely on the right track. The state machine excels at overcoming the tiresome maintenance of enum and switch architecture.