How to Get a Tiles Coordinates? (SOLVED)

How do I use tilemap.get_tile to access a tiles x,y coordinates?

I’m using a loop to create a grid of tiles and at the same time would like to log each of the tiles coordinates into a table.

I feel like this is very basic but I’m struggling. Basically how do I access a tiles coordinates? I’m used to using game objects that have transforms that can be easily accessed but this just seems backwards, lol.

You can’t get a tile’s x and y coordinates using tilemap.get_tile(). Instead, it has to be passed as an argument to the function .

If you are using a loop to set the tile, then you **have ** access to x an y coordinates of the tile, in the form of loop variables. You just need to insert them into the table :slight_smile:

1 Like

I guess I’m struggling with the syntax of how to go about doing this. Are there interactive websites to learn lua so I can learn the language better? This helps some but I need more examples. https://www.defold.com/manuals/lua/

This code fills a 10x10 tilemap with random tiles from 1-9, and stores the tile indices in a two-dimensional table by their x and y coordinates.

function init(self)
	local tiles = {}
	for y=1,10 do
		tiles[y] = {}
		for x=1,10 do
			local tileIndex = math.random(1, 9)
			tiles[y][x] = tileIndex
			tilemap.set_tile("#tilemap", "layer1", x, y, tileIndex)
		end
	end
end

Instead of just storing the tile index, you could put a table with whatever data you would like to have about that tile, or whatever you want.

The basic pair of loops to make a “two-dimensional” table is like this:

local t = {}
for y=1,3 do
	t[y] = {} -- Create the "row" table. Don't need this if you are accessing the table that is already created.
	for x=1,3 do
		t[y][x] = x
	end
end

-- You end up with a table like this:
t = {
	[1] = { 1, 2, 3 },
	[2] = { 1, 2, 3 },
	[3] = { 1, 2, 3 },
}
-- I usually loop through Y first so it ends up with this layout. 
-- You can do X first so you access it `t[x][y]`, the table will just be "rotated". 
--	(...which you will probably never need to think about.)

That’s basically all your tilemap is: a table of tile indices. Tiles aren’t objects, there’s not much to them. They’re basically just an index, and I guess “h-flipped” and “v-flipped” properties, if used.


What are you trying to do that you need the coordinates for?

3 Likes

Ross answers is pretty complete and should have you covered. If you need a complete example you can check here: https://github.com/britzl/publicexamples/tree/master/examples/click_on_tilemap

2 Likes

Thank you for the very thorough examples Ross. I’m wanting to now tile coordinates so when I create my grid as the grid is filled in at certain points the tiles can look around and see what their neighboring tiles are. For example if a tile is ‘grass’ there’s a 25% chance that a ‘mountain’ tile will spawn next to it. And if there’s a ‘mountain’ tile there’s a 60% chance that another ‘mountain’ tile will spawn next to that one, etc…

Of course using perlin noise as an option and I have looked at the infinite_map example but I’m not sure how to control what tiles will be spawned next to each other. For example I wouldn’t want a ‘mountain’ tile to spawn in the middle of some ‘water’ tiles.

Maybe I’m going about things totally wrong. Dritzl has mentioned that a tilemap is the way to go. There will be thousands and thousands of either tiles or really small game objects. My grid size is 20x20 pixels.

I got a little carried away with this and made a sample project that might be helpful. Use anything in it however you like.

Tilemap Terrain Gen Test.zip (32.0 KB)

First it just fills the map with random tiles. Then it loops over the whole map again to apply rules to each tile. I added a rule about adding forests near adjacent forests, just to show how easy it for things to get out of hand with this method.

Click to show animated Gif

Tile_Terrain_Gen

To be honest I don’t think you’ll get very far using this method for generating terrain (if that is what you’re trying to do). I think the standard method is to generate a height map with noise and then calculate everything else based on that.

6 Likes

Ross! This is freaking awesome! I’m going to learn tons and tons from this.

A couple noobish questions. Please bear with me… you’ve been fantastic.

In the function init(self) where do things like self.stepCount = 0 and self.stepFunc come from? I’m assuming they are variables but how is that syntax different from stepCount = 0?

And relating to the above what about self.tiles.data = { url = “#tilemap” }? I see the table variable tiles but where does data come into play? Are these functions storing instance data or something else?

Something else you have tile = tiles[y][x] is putting y before x just a personal decision or is there a logical reason for y being first?

Again this is all fantastic and very much appreciated.

I’ll look into height maps and perlin noise. The infinite_map project should help me with that.

1 Like

’self’ and variable scoping:
Check out this thread: Explanation of the "self"argument for dummies
Also make sure you’ve read: Locals, globals, and lexical scoping.

In this case I could have made self.stepCount and self.stepFunc as local variables in the base level and it would work just fine. Putting them in self just means you could run multiple instances of this script and they wouldn’t interfere with one another.

self.tiles.data
self.tiles is mainly my 2D array with the data for each tile. Since I’m only using number keys for the tile grid, I decided I might as well throw some extra stuff in there. In this case, the URL of the tilemap component. You need that URL to use the tilemap.set_tile function. This way, all the stuff you need is in one place, rather than hard-coding “#tilemap” or storing it in a separate variable somewhere. The only place I actually use it is in my own “set_tile” function. In general, keeping your pieces of code as self-contained as possible will keep it more organized and help prevent weird bugs.

Y before X
This is 99% a personal preference. I sort of mentioned it before. It means your table will have Y as the “row” and X as the “column”. The only thing it actually affects is the direction you will loop over the table. If you put X first then it will loop from left-to-right instead of bottom-to-top (with the same code, but you can change how the loop works if you want).


There’s lots of articles around the internets about procedural generation, and many of them are not language or engine-specific. A lot of the terrain ones are talking about 3D terrain, but the same methods will work for 2D terrain, just a difference in the final, graphical output.

3 Likes

You’re awesome. Thanks for taking the time to explain and for the links.

1 Like