Tuesday, 15 May 2018

Sporadic Godot Tutorials - Tile Sets and Autotiling

Well, because I need to get popular somehow and I'd rather not start up some kind of horrible controversy involving throwing eggs at people in a public space while screaming my YouTube URL, my only other option seems to be to make more tutorials. This isn't the classic "Gitting Gud At Godot" stuff because that was kind of dense and I feel as though there was a kind of progression from simpler material to more complex tutorial.

This "Sporadic Godot Tutorials" thing that I'm doing right now is gonna be a bit all over the place compared to that, and I'll probably opt to explain more specific things. Hell, I don't even know if I'll ever do another one of these so I don't know why I'm framing this as a series but if you have anything that you desperately need explained, then send me a message or a comment and I'll see what I can do!

So let's get down to business. I assume that most people reading this know what a tile set is, but for the purposes of completeness I'll give a brief explanation here.

In Godot, there are two components to a tile system. One of which is the tile set, and one of which is the tile map. The tile set is kind of like a bunch of generic ingredients (flour, sugar, water) whereas the tile map is what you actually do with them, or specifically, a literal grid of the tiles which are defined in a tile set.

Here's an example of a tile set sprite from a game I made, Mushroom: The Ruckus:


 (sorry about the trailing whitespace!)
As you can see, there's a bunch of tiles here, each of which is a 16x16 tile. This is just saved as a .png file and placed into some folder in the project. However, we haven't finished creating a proper tile set as far as Godot is concerned, so let's get into the engine.

Create a new scene and save it as something like "tileset.tscn". This is something you should keep around- that is to say you shouldn't discard this as soon as the tile set data is generated!

Create a tree root node of type Node and then add some sprites. Each sprite you create will equate to one tile in the editor, with some exceptions that I'll get onto in a moment. However, at the moment we're at a cross-road. If you want to figure out how to do autotiling, you're gonna have to skip ahead of this bit. If you don't know how to do even normal tiling yet, then I'm about to explain that bit so stick around for a moment.

So for a standard tileset, add some Sprite objects and name it something unique. The name you give each Sprite will correspond to the name it is given in the tile set itself, so make sure that it's informative and clear.

Also, if all your tiles are stuck together in one big .png like mine are above, you're going to have to load that .png into each Sprite and set the region. You can do this by selecting the Sprite, scrolling down to "Region" and make sure it's enabled then set the Rect. This value is basically just a value that corresponds to a rectangle of the Sprite that is going to be displayed, so the X and Y parts are the position of the top left corner of the rectangle and the W and H parts are how wide and tall it is, respectively. It should look something like this:



One more thing to note is that in order to create tiles that have collision, you'll need to add a StaticBody2D node as a child of the Sprite. Also, you'll need to add a CollisionShape2D with the appropriate shape in order to map what the collider should be and then you're good to go.

So yay, you've done it! You've created a tile set- well, nearly. All you need to do now is to generate the .tres file(which stands for text resource, I think) which can be loaded by a TileMap node in another part of your project.

This is super easy, you just have to go to "Scene" in the top left, move down to "Convert To..." and click "TileSet". Save your new tileset resource as something memorable like "tileset.tres", create a TileMap somewhere else, load "tileset.tres" into your TileMap and you're good to start placing some tiles!

Now, onto AutoTiling!

So at this point and regardless of whether you want to, you're gonna have to put all the tiles that you want involved in this autotiling stuff into the same .png file.

Also, you're going to have to open your "tileset.tscn" scene file and create a new Sprite that loads that entire .png into it. This is important: Don't set the region like you might done previously! From my experience that'll mess things up for you. Just convert this scene to a tileset resource as described above and load it into a TileMap. You're definitely not done yet, though.You've yet to even begin the real AutoTiling work!


So you've created a TileMap that has the Tile Set property set to your lovely tile set resource. Click on that resource to open it in the inspector, scroll down to the tile that's holding the whole tileset and tick the "Is Autotile" box, as shown to the left- I've named my tile "AllTiles", since it holds all the tiles.

Next, you'll notice that a button that says "Autotiles" has appeared at the bottom, next to the "Output", "Debugger", "Audio", "Animation" or whatever other buttons you might have down there. Click that, and it'll open the AutoTiler menu.

Before we do anything here, go to the left hand column (where it would normally list your tiles) and find the "Properties" menu just below it. Set "Bitmask Mode" to 3x3 and Tile Size to whatever size your tiles are. Mine's 64x64, for instance.

Now that you've done that, let's get into what all this crazy stuff in the AutoTiling menu means. The first menu is "Icon", and that one's pretty easy. It's basically the default tile to show if the autotiler can't work out which tile to place. Just pick whichever one happens to work for you, but I picked this one by left clicking it:


Now for arguably the most important menu, the bitmask menu. This one is the one that decides how your tiles are automatically selected while they're being placed. Each time you click, you'll notice that it creates a little red box.

Each tile has 9 potential spaces (with a 3x3 bitmask, if it's 2x2 then it's only 4) to place a red box. Each red box basically means "put me here if there's a tile in this position relative to me". This is a bit confusing to get your head around at first, but just carry on.

Pretty much any tile that you want to show up needs a red box in the center, because that center red box represents the tile itself. Here's what my bitmask screen looks like:


Let's take the line of tiles in the middle first. The tile at the very top will only show up if the tile directly below it is also filled in, so I placed one red box in the center and one in the center bottom position. Similarly the one at the very bottom will only show up if the tile directly above it is filled in, so I placed a box in the center and a box in the center top position.

Let's take the top left corner of that blob to the left-hand side. That corner will only show up if 1. the tile to the right of it is placed, 2. the tile below it is placed and 3. if the tile to the bottom-right is placed. Therefore, I put a red box in the 1. center-right position, 2. center-bottom position and 3. bottom-right position.

I'm not sure if I've made this very clear, but just mess around with these things in mind- you'll get the hang of it soon enough.

For these tiles, I didn't set any collision because they are meant to be walked all over by everybody else. However, if you did want to set collision you'd have added a StaticBody2D with a BLANK CollisionShape2D node to the Sprite back in "tileset.tscn", and then you'd go to the Collision menu and drawn in collision shapes for each tile. That bit's pretty easy but also hellishly buggy as of Godot 3.0.2, so good luck. Changing settings randomly, node hierarchy, saving resources and loading them again- it's a bit of a mess and I'm pretty sure it's gonna be fixed in 3.1, but for now it's really a "fuck with it until it works then never touch it again" type thing.

I don't even know what the Occlusion menu does but I'm pretty sure it's to do with lighting/shadows so I haven't and will not touch it. Sorry!

Navigation is similar to Collision in that you can draw polygons onto each tile to map out a nice NavigationPolygonInstance that you don't have to draw manually after placing the tileset. It isn't always useful, since all of the tiles above are places that I don't necessarily want enemies to automatically pathfind through- for instance, if there's a solid house on grass, I'd rather the enemies look to get around the house rather than straight through it.

The Priority tab is actually quite cool. Basically,if you've mapped multiple tiles with all the same bitmask rules then it'll randomly select one of those tiles to place when the conditions are met. However, the chance of one tile being chosen over another is actually perfectly random unless you modify the chances of it being chosen in the Priority tab.

When selecting a Tile, it'll highlight the other tiles with the same placement rules and it'll give you a fraction of how likely it is to be placed compared to the other tiles. You can select a tile you want and use the up or down arrows next to the text field to modify the chances, so instead of a 1/16 chance for a tile to be placed, you can make it a 3/18 chance, as below:



And that should pretty much do it for all your tile set needs. You can return to your tilemap, select the "AllTiles" tile and start placing and it should start AutoTiling for you. If you want to know anything else about TileSets/AutoTiling/etc then let me know, if you want a tutorial on another specific engine feature then also let me know then. 

Thanks for reading, and good luck with the autotiling!

No comments :

Post a Comment