Tag: Gamedev

TileMap – How To Get ALL The Tiles

If you’re building a 2D game in Unity3D, odds are you’ve come across the TileMap component. The TileMap is a powerful tool that allows you to create a grid of tiles that you can render your tiles with instead of hand-placing individual game objects with sprites. It has a host of built in functionality that you might otherwise find yourself manually writing, like mapping coordinates to particular cells on a map. And what’s even cooler about using a TileMap? You don’t need to handroll your own editor to paint tiles! I think I’d pass on having to do that. But have you found yourself in a situation where you want to get all of the painted tiles on a TileMap? You may have found it’s not quite as obvious as you’d have hoped!

What We Have To Work With On A TileMap

As I mentioned, a TileMap can do a lot for you. In particular, I found myself wanting to get all of the cells that have a Sprite associated with them and what that Sprite actually is. We can use the built in method GetSprite for this:

var cellPosition = new Vector3Int(x, y, 0);
var sprite = tilemap.GetSprite(cellPosition);

Simple enough. But how do we know which coordinates to use for x and y? Is it good enough to just go from 0 to a really high number on the x and y axes with two loops and hope it’s good enough? We can do better than that! The TileMap class has a handy property on it called cellBounds. This gives us an integer rectangle that defines the bounds of all of the TileMap cells that have been modified:

tilemap.cellBounds

If you have found you’re doing a lot of editing on a TileMap, you may be erasing sections to focus on another area. If that’s common, you may benefit from calling CompressBounds() to shrink this back down to the currently assigned cells:

tilemap.CompressBounds()

And with all of these, we can approach how we might tie them all together to get what we need!

Be Careful With TileMap.cellBounds And Starting From Zero!

If you have a keen eye, you’ve probably realized that we want to use two loops to go through the cell bounds on the x and y axes to get the cells we’re interested in on the TileMap. You’re spot on! But there’s something we should be careful about here!

It’s an easy mistake to make because it’s how we commonly write loops:

for (int x = 0; x < bounds.max.x; x++)
{
    for (int y = 0; y < bounds.max.y; y++)
    {
        // do stuff
    }
}

But what’s wrong with this? The starting value! You need to be careful when working in 2D space like in Unity. There’s nothing that actually guarantees your Tiles have been drawn starting from position zero on the TileMap and only going in a positive direction. In fact, in my game I had no tiles on the positive y axis! So a simple change to make sure you don’t mess up is use the MINIMUM as your starting point:

for (int x = bounds.min.x; x < bounds.max.x; x++)
{
    for (int y = bounds.min.y; y < bounds.max.y; y++)
    {
        // do stuff
    }
}

Simple as that!

Wrapping It All Up

You’re probably looking for a full-blown code snippet by now. Fair enough. Here’s what I whipped up:

public static class TileMapExtensionMethods
{
    public static IEnumerable GetAllTiles(this Tilemap tilemap)
    {
        // note: optionally call tilemap.CompressBounds() some time prior to this
        var bounds = tilemap.cellBounds;

        // loop over the bounds (from min to max) on both axes
        for (int x = bounds.min.x; x < bounds.max.x; x++)
        {
            for (int y = bounds.min.y; y < bounds.max.y; y++)
            {
                var cellPosition = new Vector3Int(x, y, 0);

                // get the sprite and tile object at the specified location
                var sprite = tilemap.GetSprite(cellPosition);
                var tile = tilemap.GetTile(cellPosition);

                // this is a sanity check that i've included to ensure we're only
                // looking at populated tiles. you can change this up!
                if (tile == null && sprite == null)
                {
                    continue;
                }

                // create a data-transfer-object to yield back
                var tileData = new TileData(x, y, sprite, tile);
                yield return tileData;             
            }
        }
    }
}

public sealed class TileData
{
    public TileData(
        int x,
        int y,
        Sprite sprite,
        TileBase tile)
    {
        X = x;
        Y = y;
        Sprite = sprite;
        Tile = tile;
    }
    
    public int X { get; }

    public int Y { get; }

    public Sprite Sprite { get; }

    public TileBase Tile { get; }
}

The above example provides a nice extension method to get you back a TileData instance for all the populated cells on your TileMap!


NoesisGUI – The Unity UI Framework That You Probably Aren’t Using!

If you’re like me, trying to create user interfaces in general is a challenge. So when it comes to working in tools that you’re less familiar with, that challenge basically grows to a level where it’s a roadblock. For me, trying to create user interfaces in Unity3D is basically the perfect example of hitting this roadblock! That’s not to say the UI tools that are available in Unity3D are bad, but my skill level is essentially reset to zero when working with these tools. Fortunately I came across this little gem called NoesisGUI that enables WPF inside of Unity3D!

I plan to do a few updates on this either via YouTube or short blog posts, but NoesisGUI has essentially unlocked my ability to create user interfaces inside of Unity3D. You can find my intro video here, or watch it directly below:

Now I’m still not a UI expert by any means, but at least I get my familiar environment back. NoesisGUI has two primary benefits for me as a software developer:

  • I have access to all the WPF controls, XAML syntax, and styling capabilities that I know and love.
  • I can use tools/IDEs I’m familiar with, not sacrificing years of experience using these tools.

On the first point, for me I find it very tedious to create UI elements in Unity3D. For some good examples, I consider trying to do two pretty common things: control layout and lists of items. On control layout, I find the anchoring system and transforms a total pain to work with in Unity3D. It’s a personal preference sort of thing, but I find it difficult to navigate and get things to work as I expect. However, I know thanks to NoesisGUI I can leverage things like grids and flowing panels so I can use what I know and not try to design a layout system from scratch. Same thing goes with lists! I can use a ListView control thanks to NoesisGUI and then style/template all the controls inside of it leveraging XAML. Effectively, being able to leverage NoesisGUI to enable my experience with WPF means I can struggle with UI design instead of struggling with UI design AND how to make the UI framework work! It doesn’t fix my poor UX abilities, but NoesisGUI does allow me to do my best work at least.

The second point is around tooling. The Unity3D editor is powerful and if you watch any amount of tutorials from YouTube you’ll know that there’s no shortage of people showing how to drag and drop objects into the scene to get the result you’re after. But this doesn’t work well for my design approach because I don’t want my game to be coupled to the Unity3D engine (which I’ll need to write more about later). In fact, the more things I place concretely in the scene, the more it couples my game to Unity3D and it’s just not something I want to commit to. As a result, to decouple my UI code I found myself trying to programmatically make Unity3D UI elements and started to dream up some templating language.

Nonsense. NoesisGUI puts me back in my comfort zone and allows me to use familiar tools like Blend where I get my visual editor for my WPF controls as well as the split view with the XAML editor. Aside from a couple of minor quirks, I was able to get Blend to show things exactly as Unity3D shows them. That means I can rapidly develop my game UI inside of Blend. Along with with a bunch of other design philosophies (i.e. decoupling from Unity3D engine), this means we could literally write a couple-of-line game entry point with a WPF UI overtop of it directly in Blend and have it map to expected behavior in Unity3D. Again, more on some of those design philosophies later, but NoesisGUI really took it to the next level by allowing us to decouple the UI completely from Unity3D restrictions.

I plan to create more writeups and videos on how we’re using NoesisGUI in our RPG project, so stay tuned!


  • Copyright © 1996-2010 Dev Leader. All rights reserved.
    Jarrah theme by Templates Next | Powered by WordPress