A Practical Guide To Using Tiles in GameMaker


A Practical Guide To Using Tiles in GameMaker

Hi there! This is your practical guide to Tiles in GameMaker Studio 2, ranging from its use in the Room Editor to runtime interactions through GML. You will learn to create tiles and use them for level design, and to check tile collisions at runtime.

Note: You can download the Tile Sets used in this post by clicking here.

Sections

  1. Overview
  2. Tile Set Editor
  3. Room Tile Layers
  4. Automatic Tile Imports
  5. Auto Tiling
  6. Brush Builder
  7. Animated Tiles
  8. GML Usage
  9. Collision Checking
  10. Tips

Overview

GameMaker Studio 2 allows you to create “Tile Set” assets that are a collection of tiles which can be placed in a room. They allow for a faster workflow for designing levels as opposed to using objects, and are faster to render as well. 

To create a Tile Set, you first need to import a sprite that contains your tiles. Note that the top-left tile cannot be used, as a Tile Set uses that as the “empty tile”, so ideally you would want to leave that slot empty in your Tile Set: 

undefined

You can then create a Tile Set asset and assign your imported sprite to it.

undefined

Tile Set Editor

undefined

After loading your sprite into a Tile Set, you will need to adjust the settings on the right (such as the tile size, offset and separation) so that your tiles can be used properly. The separation option can be useful if there are gaps between your tiles, such as in the following image:

undefined

You can also assign the Tile Set to a specific texture group.

Room Tile Layers

Placing tiles in a room is simple enough: you create a Tile Layer and assign a Tile Set asset to it:

undefined

Selecting a Tile Layer opens another panel to the right of the IDE, where you can select each individual tile (or multiple tiles using CTRL+LMB) and paint them in the room. At the top of the room you will see several tools, similar to the ones found in the Image Editor, that you can use to design your world:

 

undefined

Automatic Tile Imports

If you have an image of a level built using tiles, such as a mockup, you can extract tiles from it using the “Convert Image to Tilemap” option under the Room menu. This loads the given image into a new Tile Layer, and also creates a new Tile Set that can be reused.

undefined

I loaded this image that shows a map built using some tiles: 

undefined

I had to adjust some properties in the importer (such as tile size, starting position) and it then generated a Tile Layer with the given image, and also created a new Tile Set asset with all unique tiles:

undefined

Let’s go back to the Tileset Editor now and look at its most exciting feature: Auto Tiling!

Auto Tiling

Any Tile Sets that have different types of terrain (like grass and dirt etc.) or walls/platforms can make use of Auto Tiling to speed up the level designing process. 

If you open the Auto Tiling menu from the Tile Set Editor, you will see that it allows for two kinds of Auto Tile Sets: one with 47 tiles, and another with 16 tiles:

undefined

You can click on the plus button next to either of them to add a new Auto Tile Set.

16 Tile Set

undefined

The 16 Tile Set allows you to place two kinds of terrains, as indicated by the light and dark areas in the template shown above. These could be grass and dirt, grass or water, etc. 

You can assign tiles from your Tile Set to each template tile, and enable the overlay to make sure you’re selecting the correct tiles: 

undefined

 

The undefined tiles are used when the corners of two different tile blocks meet. 

You can also make a Tile Set where the grey parts are transparent, such as land tiles for a platformer game:

undefined

Tip: If you are using such a Tile Set for collisions, make sure to assign the top-left tile to the last grey template tile, as it allows for easier collision detection (since the tile ID would return 0, the equivalent of false).

47 Tile Set

undefined

This is the lesser used Auto Tile Set, particularly because it is more complicated and requires a larger amount of tiles. If used correctly, it allows for narrower tiles and supports more tile combinations. Here is an example of a Tile Set that can be used with the 47 Set:

undefined

Such a Tile Set can be used to create intricate levels that use less tile space, as seen below:

undefined

Brush Builder

The Brush Builder allows you to create groups of tiles that can be placed throughout a room, such as any repeating sections of your levels. All the tools from the Room Editor are available here, including Auto Tiling.

undefined

You can use these custom brushes in a room, just like you would use regular tiles. So basically you are creating tiles using tiles! 

undefined

 

You can also edit your brushes directly from the Room Editor by enabling “Editing Mode” at the bottom. 

Animated Tiles

You can create animated tiles as well, however it doesn’t work like Sprite animations since Tile Sets don’t allow multiple “sub-images”. Instead, the frames of an animated tile must be contained within the Tile Set itself, and those individual tiles can then be selected as frames: 

undefined

Your animated tiles can be found under the “Libraries” section of your Room Editor, like your Auto Tile Sets, and can be placed in the room just like regular tiles.

GML Usage

Finally, let’s talk about how tiles can be used in GML. We’ll first need to understand the concept of Tile Maps.

Tile Maps

Each Tile Layer has a Tile Map attached to it, and placing tiles on a layer puts them into its Tile Map. The Tile Map is what you see in the Room Editor and in the game as well. It functions as a grid, where each cell can hold a tile. 

The Tile Map ID for a layer can be retrieved using layer_tilemap_get_id()

var _tilemap = layer_tilemap_get_id("LayerName"); 

There are many Tile Map Functions that you can run on the returned Tile Map ID, to get a tile on the layer or to change a tile. For example, you can run tilemap_get() to get the tile data at the given cell coordinates, or tilemap_get_at_pixel() to get the tile data at the given room coordinates. There are similar “set” functions that can be used to change tiles.

Tile Data

The tile data returned by tilemap_get() is usually the tile index, which is assigned to each tile in a Tile Set starting from 0:

undefined

However, the returned tile data is only equal to the tile index when it has no extra data. For example, you can apply rotation or mirroring to the tile data, and apply the modified tile back to the Tile Map. Such a modified tile will not be equal to the tile index anymore as it has extra data now. 

To avoid such issues and get the correct tile index from a cell, use tile_get_index() on the tile data returned by tilemap_get(). For example, let’s say you want to check whether the player is standing on a water tile, and let’s assume that the index for that tile is 4. You could do a check like this: 

var _tile = tilemap_get_at_pixel(_tilemap, x, y);
var _tile_index = tile_get_index(_tile);
if (_tile_index == 4) // In Water

You could also create an enum to store your tile indices!

Collision Checking

Tile collisions mostly involve checking if there is a tile at a given position, but it also depends on how your Tile Map is set up. The easiest way is to assume all tiles in a Tile Set are collidable, so if there’s a tile, there’s a collision, otherwise there is not. This makes our check this simple: 

if (tilemap_get_at_pixel(_tilemap, x + hsp, y + vsp)) 
Note: hsp and vsp are added to x and y because you usually want to check for collisions where the instance is going to move. 

However, if there are only some tiles in your Tile Set that need to have collisions, then you need to read the tile’s index as well and make sure that it is the tile you want (like we did in the water tile example above). 

Now this only covers checking for one point, however instances have a bounding box. My usual solution for that is to check for tiles at all bounding box corners: 

// Bbox coords
var _left = bbox_left + _hsp;
var _top = bbox_top + _vsp;
var _right = bbox_right + _hsp;
var _bottom = bbox_bottom + _vsp;

// Check collision
var _collision = tilemap_get_at_pixel(_tilemap, _left, _top) ||
			tilemap_get_at_pixel(_tilemap, _right, _top) ||
			tilemap_get_at_pixel(_tilemap, _left, _bottom) ||
			tilemap_get_at_pixel(_tilemap, _right, _bottom);
Note: If your game uses grid-based movement, then you can simply use tilemap_get() to check for collisions at a cell, avoiding the need for bounding box checks. 

Keep in mind that this could cause issues if there were a tile smaller than the instance’s bounding box, as it could just pass between the corners. To work around that you can add more checks in the middle of each bounding box edge.

Tips

We covered reading Tile Maps created in the IDE, but you can also generate them at runtime. Use layer_create() to create a new layer and layer_tilemap_create() to add a Tile Map to it. You can then assign a Tile Set to it and start placing your tiles! 

If you want control over how a Tile Layer is drawn, you can make it invisible and use the draw_tilemap() function to draw its Tile Map yourself.

You can also download the Tile Sets used in this post by clicking here.

Summary

There’s a lot you can do with Tiles, from creating beautiful static (or animated) visuals to building levels quickly with collision support. As always, the manual has the most info on every aspect of the IDE and runtime, so make sure to check out these pages: Tile Set Editor and Tile Map Layers.

Let us know what you think of Tiles on Twitter @YoYoGames and share your creations using the #GameMakerStudio2 hashtag.

Happy GameMaking!

Written by Gurpreet S. Matharoo

Lead Technical Writer at GameMaker, Gurpreet creates documentation and tutorials to make game making easier for you. He loves using the computer to bring new things to life, whether it's games, digital art, or Metal music.