Unity3D - Get ALL of the Tiles in a TileMap!
May 16, 2021
• 2,762 views
UnityUnity2DUnity3DTileMapExtension MethodscsharpdotnetGameDevGameDevelopmentIEnumerable2D Tilestilemapstilemaps in unityunity 2dunity 2d tutorial2d game dev2d game developmentunity tutorialunity tutorialsunity3d tutorialhow to get tiles in unityhow to make a tilemap in unityhow to make a tilemap in unity 2dunity 2d tilemapsunity tilemap tutorialunity 2d tilemap tutorialgame devgamedevunity tilemapgame developmenttilemap unity
Here's a quick video on how you can write your own extension method for getting all the assigned tiles in a TileMap!
Prefer to read the blog?
http://devleader.ca/2021/05/18/tilemap-how-to-get-all-the-tiles/
Want to see more videos about Unity3D?
https://www.youtube.com/watch?v=p_OEifeDwVo&list=PLzATctVhnsgjdhQzyvYoxtmVQS5RH4KNm
My Social:
LinkedIn: https://www.linkedin.com/in/nickcosentino
Blog: http://www.devleader.ca/
GitHub: https://github.com/ncosentino/
Twitch: https://www.twitch.tv/ncos...
View Transcript
i just wanted to do a quick video on this because i had to do some googling to find it and i figured i'd put this video together so maybe it'll save someone else sometime in unity i'm trying to write some code that can take advantage of looping through the tiles on a tile map so that i can do some work with only the tiles that i've assigned so in particular i'm trying to work on a little map editor for a 2d tile based game and basically through some serialization efforts i want to just be able to serialize and deserialize things but i only want to focus on the tiles that i've painted so i just want to kind of show you this is the code that i'm kind of writing to be able to to do that serialization work it's not complete or anything but
what i want to dive into is essentially this little extension method i wrote and all that it does for us is that it will loop through the tile map which is a grid and kind of get all of the tiles that actually have something assigned i couldn't find anything built in and i figured i kind of walk through what that looks like so with that said i'm going to go into the implementation of this and you'll notice it's in a static class in a static method and if you're not familiar with extension methods it doesn't have to be an extension method you could pass in the tile map on a static class and do it however you want but the extension method like i said if you're not familiar just jumping back kind of lets us write it so that it looks like it's a
method that exists on the object already right so otherwise if you didn't want to do an extension method you could have it look like that like something like right so i didn't want to have a static class and then have this method and pass it in i kind of just wanted it to look like it was supposed to be built in already okay so with that said what does this do for us um well basically we need to enumerate the tile map and only look for tiles that are assigned some type of sprite or some information associated with it for my game right now only kind of focused on i only care if there's a sprite there i'm not doing any other data attached to the tiles just yet kind of keeping that in mind but for what you're looking at in this code below
when we get to it it's really only focused on trying to get the sprite but anyway what we want to do is only look for the cells that are assigned so there is this property available to us called cell bounds on the tile map and it says returns the boundaries of the tile map in cell size so you'll see that the return type is bounds int and this is really useful because um all the the stuff in world space for unity is floating point um so when we're talking about the the cells of a tile map we're not looking at say like um sell like you you don't say like sell 1.2 at and um like 3.7 we're not looking at a cell at that location it's going to be an integer value so the bounds give us this integer based um ability to index
into the tile map um and in particular what's really good about that is it's only going to give us the actual um sort of rectangular bounds that are associated with assigned tiles right that's what we're interested in here so something to point out i haven't had to use this yet but something to consider is there is this method called compress bounds so if you're thinking about doing a map editor and you have to erase some um some sprite assignment somewhere you're kind of painting you're like oops i don't care about that um you can call compress balance to essentially re-shrink the bounds to only be the assigned tiles otherwise i believe it kind of just keeps growing indefinitely as you paint wider and wider so if you're undoing stuff that's further out consider calling compressed balance to make this a little bit more efficient so
what we're going to do with compressed balance is we want to go basically through all the x coordinates and y coordinates so that's why we have this double for loop here but i think the most important part that i want to call out about this um and this is something that i think people can miss easily when they go look this up online is a lot of examples i see look like this we're very used to writing for loops that start at zero right something like you kind of learn early when you're programming is like you're going to do a for loop like in i equals 0 i plus plus right um because we're learning how like a lot of stuff in programming is zero based indexing so we always start at zero instead of one so there's this really big focus on starting our
loops at zero and in particular for this it's actually not what we want to do and that's because your tile map is not necessarily located at zero and going to a positive bounds in particular and i i missed this uh when i first put this in i was like why is it not getting all the tiles that i'm interested in and it's because my tile map is actually the the y values in particular are negative so it was trying to go from zero right here right because this is what it used to say zero and my bounds max y was actually a negative value so it would never do anything so i just want you to keep that in mind that when we're looking at this you want to go from your minimum on the x to the to the maximum on the x i
started there and then do the same thing for your y values right because in particular in my case at least this was going from like negative 16 or something up to zero right if you start at zero it does not take into account negative values so just keep that in mind okay so hopefully this part um is is clear now this is i think the most important part that i wanted to to get in front of people is consider the bounds and this is how you get the bounds and then from there the methods that you have access to on the tile map i think kind of do everything else that you need for this in particular i'm really like i mentioned only focused on this sprite that's all i care about for my serialization purposes however you can get the actual tile base right
so you can get the tile base from this position and you can see that we're building that from the x and y coordinate here the the z is not really a factor here i haven't had to do anything with tile maps and z positions or i don't even know if truly you can but maybe something else to follow up on but anyway just kind of looking at this two-dimensionally i'm not doing anything in my game yet with any tile data associated here i just kind of have this for illustration purposes and later on down the road if i want to pull anything else from the tile i can so another thing you'll notice is that after all this is done i'm just checking to see basically like is there actually a tile here just like a little quick sanity check is if not i personally
don't care if it's not contiguous i'm not i'm not worried about trying to serialize like a contiguous block of cells even if some of them are unassigned i actually want to completely ignore them and only focus on assigned cells so if for example they were sporadically painted cells on my map i only care about the painted ones not the null values so i am checking that if you want you can design this so that it does not do that that's totally up to you but you'll notice that i have this tile data that's being returned and this is something i just made it's a little dto like a data transfer object that it's only going to contain some extra information for us so that i i have a complex return type i didn't just want to return the sprite i actually care about the x
and the y coordinate associated with the sprite and like i mentioned maybe other tile data down the road so if we look at what tile data looks like it's extremely simple right it's just um the x and the y coordinate like i mentioned the sprite and the tile and just some getters on that so nothing fancy but i just wanted to point out that this is a class that i made so if you're looking at this code you might not see tile data because i made that and i think the only other thing i wanted to call out about this that i like and i like thinking about this when i'm designing apis for things is that you'll notice i have an i enumerable here and i do that because i like designing codes such that if i wanted to call this api i could
terminate the enumeration early in my particular case right now the only use case i have at this moment for serialization i want to walk through all the tiles right so i don't care if this is an innumerable or a list or whatever for the one instance i have of this right now however in the future if i wanted to say look for a particular tile what i could do is call get all tiles and then use link to extend that and filter out only the tiles i care about maybe i just want to do tiles dot any right so get all tiles dot any if you want to see what that looks like um it would be just like this without the slash um so if i wanted to do this the nice thing about using an i enumerable is that it will stop enumeration
as soon as it finds one right so if it finds one thing it won't keep enumerating if we were to do a list then it's going to go back to the extension method if this were a list or a collection and not just an enumerable we can't take advantage of this yielding so this is something if you're not familiar with this there's lots of information online about uh i innumerable and being able to yield return and doing early like termination of enumeration um i can probably create a video for that as well but i just wanted to point out that instead of doing something like this and then forcing like building up a list inside here right doing something like this tile data and then adding each individual tile and then returning it at the very end um this is it's not like this is
wrong right oops sorry all tiles um it's not like this is wrong or anything but when you write code this particular way you're unable to yield return i have to build up the whole collection once and then if i want to go filter that i'm doing another round of enumeration through this so if you have a ton of tiles you may want to reconsider that so i just wanted to point out that that's why i use an i enumerable here so i'll kind of undo that quickly and then just do a quick summary over uh everything we just talked about but just to recap and get rid of the list there so it's an extension method so that we can make it look pretty when we're calling it that's really the only benefit the cell bounds are going to focus on the painted tiles only
if you need to you can call compressed bounds to help reduce that and make it a little bit more optimal you do want to use your min x and min y on your for loops so that that way if you're starting at zero you're not messing up and missing things on your tile map these double loops will help handle enumerating your rows and columns of the tile map and then we can call the built-in stuff easily on the tile map with this position to return those and like we just talked about at the end enumerable so that if we want we can leverage yield return and terminate early so that's it i hope that helps um just wanted to recap and kind of share with you the the things i learned while doing some googling to to find this so thank you
Frequently Asked Questions
What is the purpose of the extension method mentioned in the video?
The extension method I created allows us to loop through a tile map and retrieve all the tiles that have something assigned to them, specifically focusing on the tiles I've painted for my map editor.
Why should I use min and max values for my for loops instead of starting at zero?
You should use min and max values because the tile map may not start at zero. In my case, the y values were negative, so starting at zero would cause the loop to miss those tiles. It's important to account for the actual bounds of the tile map.
What is the benefit of using IEnumerable instead of a List in the code?
These FAQs were generated by AI from the video transcript.Using IEnumerable allows for early termination of enumeration, meaning if I find the tile I'm looking for, I can stop the process immediately. This is more efficient than building a complete list and then filtering it later.
