• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GML How to programatically draw a tile cell to instance layer?

murchie85

Member
Apologies that this answer is no doubt simple, but everything I google and youtube, just shows how to draw tiles using the editor manually (brushes/libraries/autotile etc).
From the documentation I know i can grab a specific tile using tilemap_get , but how would I then draw that to an instance layer programatically?

I appreciate the example below I could just make them into one big animation and select the frame and set speed to 0 - however i'm trying to understand and learn the approach with tiles for more complex procedurally generated backgrounds later.

Many thanks




Screenshot 2020-07-29 at 18.36.12.png
 

Tony Brice

Member
Ok, if I'm understanding what you want to do correctly. This should place a tile in the top left corner of your room.

I've not used tiles in a while but this was how I used them from memory.

Code:
x = 1; y = 1;
var l = layer_get_id("LAYER_NAME"); // Layer name is the room editor layer your tiles are to be drawn on.
var tileMap = layer_tilemap_get_id(l);

tilemap_set(tileMap, TILE_ID, x,y); // TILE_ID is the number of the tile you want to place.
 

TheouAegis

Member
Why would you want to add it to an instance later? You typically would want to add it 2A layer that possesses a tile map. If you wanted to for whatever reason added to a layer that does not already possess a tilemap, you can create a tile map on the target layer using layer_tilemap_create().
 

murchie85

Member
Ok, if I'm understanding what you want to do correctly. This should place a tile in the top left corner of your room.

I've not used tiles in a while but this was how I used them from memory.

Code:
x = 1; y = 1;
var l = layer_get_id("LAYER_NAME"); // Layer name is the room editor layer your tiles are to be drawn on.
var tileMap = layer_tilemap_get_id(l);

tilemap_set(tileMap, TILE_ID, x,y); // TILE_ID is the number of the tile you want to place.
Hi, thanks if "LAYER_NAME" is the room layer (in my case it's an instance layer called "Instances"), where do we specify the tileset?

Why would you want to add it to an instance later? You typically would want to add it 2A layer that possesses a tile map. If you wanted to for whatever reason added to a layer that does not already possess a tilemap, you can create a tile map on the target layer using layer_tilemap_create().
hey Aegis, I think it's my lack of understanding on the issue, as my aim is to have a layer be populated dynamically with tiles as the background will be continuously scrolling up and changing- from all the tutorials I have seen, they use a static tiles where they brush or use autotiles. However in my case that is unfeasible as the background could be scrolling for minutes and needs to be generated dynamically.
Is it possible to have a tile layer move with vertical speed like a normal background?

Ok, if I'm understanding what you want to do correctly. This should place a tile in the top left corner of your room.

I've not used tiles in a while but this was how I used them from memory.

Code:
x = 1; y = 1;
var l = layer_get_id("LAYER_NAME"); // Layer name is the room editor layer your tiles are to be drawn on.
var tileMap = layer_tilemap_get_id(l);

tilemap_set(tileMap, TILE_ID, x,y); // TILE_ID is the number of the tile you want to place.
Got it working now, thanks so much!
 

TheouAegis

Member
hey Aegis, I think it's my lack of understanding on the issue, as my aim is to have a layer be populated dynamically with tiles as the background will be continuously scrolling up and changing- from all the tutorials I have seen, they use a static tiles where they brush or use autotiles. However in my case that is unfeasible as the background could be scrolling for minutes and needs to be generated dynamically.
Is it possible to have a tile layer move with vertical speed like a normal background?
To answer, yes. You use the tilemap_x() or tilemap_y() functions to scroll the tilemap.

You can add all your tiles to the room at the start of the room. I never did like how GMS2 restricts the tilemap to the room size; it's just plain stupid since you can clearly have tiles outside the room and have a tilemap larger than the room. Since you are just scrolling in one direction, go ahead and expand the tilemap at the start of the room and add all the necessary tiles if it's not going to be randomly generated.

Code:
var h = tilemap_get_height(TILE_MAP);
tilemap_set_height(TILE_MAP, h * number_of_tiles_in_full_image);
for(var i=1; i<number_of_tiles_in_full_image; i++)
    tilemap_set(TILE_MAP, array_of_tiles_in_full_image[i], 0, i)

//You can't  have negative tilemap indices, so if you are scrolling up, you'll be writing the tilemap
//from the last frame to the first frame, so  you'll need to move the tilemap down to the first frame
tilemap_y(TILE_MAP, tilemap_get_height(TILE_MAP) - h;
There should be no issue at all with this method. I tested on Windows 10 with a tilemap 518,144 pixels wide (8096 tiles) with no change in FPS relative to a 4032 pixels wide tilemap.

Alternatively, you could use tilemap_y() to scroll the tilemap, then every n steps snap the tilemap back to 0 and update the tilemap. I think this would be far more likely to cause slowdown than just expanding your tilemap to 8000 pixels tall. That doesn't mean keep your image 8000 pixels tall, that means break your image into multiple tiles and then make the tilemap 8000 pixels tall so you can have all of those tiles in the room at the same time.
 

murchie85

Member
To answer, yes. You use the tilemap_x() or tilemap_y() functions to scroll the tilemap.

You can add all your tiles to the room at the start of the room. I never did like how GMS2 restricts the tilemap to the room size; it's just plain stupid since you can clearly have tiles outside the room and have a tilemap larger than the room. Since you are just scrolling in one direction, go ahead and expand the tilemap at the start of the room and add all the necessary tiles if it's not going to be randomly generated.

Code:
var h = tilemap_get_height(TILE_MAP);
tilemap_set_height(TILE_MAP, h * number_of_tiles_in_full_image);
for(var i=1; i<number_of_tiles_in_full_image; i++)
    tilemap_set(TILE_MAP, array_of_tiles_in_full_image[i], 0, i)

//You can't  have negative tilemap indices, so if you are scrolling up, you'll be writing the tilemap
//from the last frame to the first frame, so  you'll need to move the tilemap down to the first frame
tilemap_y(TILE_MAP, tilemap_get_height(TILE_MAP) - h;
There should be no issue at all with this method. I tested on Windows 10 with a tilemap 518,144 pixels wide (8096 tiles) with no change in FPS relative to a 4032 pixels wide tilemap.

Alternatively, you could use tilemap_y() to scroll the tilemap, then every n steps snap the tilemap back to 0 and update the tilemap. I think this would be far more likely to cause slowdown than just expanding your tilemap to 8000 pixels tall. That doesn't mean keep your image 8000 pixels tall, that means break your image into multiple tiles and then make the tilemap 8000 pixels tall so you can have all of those tiles in the room at the same time.
That is excellent info, just what I am looking for, I take it then because of GSM2 restricting tilemap to the size of the room it's standard for people to make the room far bigger than the view port otherwise would end up having a high volume of tilesets to flick iterate right?
By the way is there a simple way to clear all the tiles in a tile set? I am adding tiles programatically but sometimes just want to clear them as to be transparent, at the moment I am using tilemap_set with the index value of 0 and applying it to all cells, although it seems a bit inefficient and have been looking for a built in function that clears all cells.
 

TheouAegis

Member
You could also use layer_tilemap_destroy(), but then you'd need to create a new tilemap eventually. Or you could just destroy the layer, but then you'd need to make a new layer eventually. At least tilemap_clear() is more utilitarian. šŸ™ƒ
 
Top