Use tiles as special triggers / positions cues (SOLVED)

Hi!
I’m trying to make a simple platform game.

I was wondering…
It is possible to tag or identify special tiles and use them into the code?
It is also possible to set a collision group in a tile source to a trigger type of collision?

I my case I want to be able to set some special invisible tiles for indicate the start position of the player in the level and an end of the level insivisible trigger.

Actually for implementing the trigger in the level collection I have created another parallel tilemap with a custom collisionobject set to trigger, but it is not very handy because you lose the level architecture reference.

There is any solution?
How would you implement this case?

Sorry I’m a little noob in game development and with Defold!
Thank you so much! :slight_smile:

Yes, a simple solution is to use a Lua table like this:
local metadata = { [tile_position] = { metadata_1 = <value>, ... }, ... }
When the player collides with a tile whose position is in this metadata table, you can pull the data from the table and interpret it however you wish.

Here’s another explanation from a while back: Any way to add metadata to tiles in the tilemap editor?

2 Likes

Thank you klaytonkowalski!
But, if I understood well, this solution require to place some graphical tile on the tilemap and code a behavior in the background based on a fixed tile position.

But what if the position of the tile change?

I was imagining that if I need to split the work with maybe a level designer… I want to build basic levels building blocks and let him free to experiment.
It is actually possible to code a logic based on a particolar type of tile present in the tilemap?
Maybe with some plugin?

I would create an extra layer in the tilemap and read that when the level/map is loaded. I would clear the tiles in that layer as I read them and based on the content I’d create game objects of the required type.

4 Likes

Thank you britzl!

Are you referring at these API?

Tomorrow I will try to do something… But from which property I can distinguish the tiles from each other?

Yes, exactly!

What do you mean?

So, would you say these are the conventional steps?
Setup
1 - create your tilemap with 1 extra layer (info) which only contains tiles that represent the trigger information.
2 - Have a reference table to translate these tiles to the triggers when needed.
3 - Create game objects that correspond to what you will want as interactions on those tiles.
4 - Setup collisions on game objects and player to detect interactions

Runtime
1 - read in bounds of the tilemap
2 - iterate through those bounds to create a lua table of the tilemap, getting the content of the info layer.
3 - generate game objects that have whatever characteristics you need on those tiles
4 - clear layer as you iterate through (set_tile to 0)

1 Like

Yes, I believe that will work pretty well!

1 Like

What do you mean?

Sorry if I was not clear.

Taking the following example:

The purple tiles are “special tiles” that in runtime are not visible.
In runtime I want, at the start of the level, put the player where the “GO” tile is.
Also I want to load the next level when the player reach the “chessboard” tile (by trigger collision).

For achieve this I can try to follow the SpencerWF suggest… but sorry… I really not understand how to link the reference table to the special tiles without using the coordinates of the tiles placed on the tilemap (which means changing the code when the design changes)… what can be otherwise the “key” for link tiles with information table?

And, to clarify my doubt, how I can distinguish the “GO” tile from the “chessboard” one if they are in the same layer? Maybe by the tilesource position?

What about using a layer as a tag, creating a special layer for each desired behavior of the tiles inside the layer?

In my example can something like this:


level1.tilemap

  • gound-layer --> all white square tiles
  • special_level-start --> “GO” tile
  • special_level-end --> “chessboard” tile

With this setup at runtime I can, following your suggestion, read all the tiles from special layers and translate them into a logical behavior based on the layer of belonging.

But what about collisionobject? Only can take an entire tilemap for source instead of single layers…
I should assign no collisionobject and create all dinamically in runtime?

Can be a solution? What can be a better solution?

Thank you all again!

Hey!

It is surely possible and the approaches above are very good!
You can create a tilemap with special tiles, that will be used to spawn some other elements and yes, you can do it on a separate layer or not - but in some cases replace the special tiles with some other tile. You can check for each tile in the tilemap and “parse” it however you want :wink:

Take a look for example on how @benjames171 is creating level for example in his open source: https://github.com/benjames-171/defold-games/tree/master/Crystal%20Caverns.
In level.script you will find functions to spawn certain obejcts in place of tiles that are purposely placed in a tilemap before. Then there is a parse function that goes for each tile in a tilemap and do a certain action if gets a special tile number. It would be the best that your tilesource remains unchanged, because with each change you need to remember to change values in the script as well :wink:
In data.lua you will find functions to convert coordinates from world to tile and back.

Ben’s approach is specific, but it allows to conveniently and quickly create levels in tilemap editor only (or in Tiled/Tilesetter).

Of course, you will need to check for a collision with the whole tilemap, but if the collision occurs, you will parse the map and check with which tile player collided actually basing on the position of the character.

4 Likes

Thank you @Pawel !
That code is very intresting and just what I was looking for! :grinning:

But from which property I can distinguish the tiles from each other?

I just understood now looking in the code that tiles are identified in the tilesource by an index based on their position, from up to down, left to right.
I said that I’m noob, so I didn’t know this! :roll_eyes:


My last doubt is… it is possible to have also trigger and static collision in the same tilemap?
In this game, for example, checkpoints are handled outside the tilemap, directly in the collection.

Maybe I can use a special layer in the tilemap for triggers and at the init of the level cut out this layer and create a second parallel tilemap with this layer and a trigger collisionobject? You think can be possible with actuals API? I think I only need, in runtime, to move a layer from a tilemap to another and I’m fine! :grinning:
(looking at API manual it seem to be actually directly impossible :frowning: )

Normally maybe can not be a problem to handle checkpoints outside the tilemap, but a consistent part of the level in my game I think will be triggers (for little areas where maybe some controls are different or some physics stuff change…).

Thank you all again! :laughing:

2 Likes

At the end I overcome the problem of trigger tiles with this code:

function process_trigger_tiles(main_tilemap_url, triggers_tilemap_url)
	--[[
		SETUP:
		* Create the "_triggers" layer in your main tilemap and put in all tiles
		  that you want to affect with a trigger collisionobject
		* Create the another tilemap, the "triggers tilemap", and bring it into your collection
		  and link to it a trigger collisionobject
		* Create in the triggers tilemap two layers:
			> "bounds" : will only allow us to expand the bounds of this tilemap to match or to be greater
			  than the main tilemap. For this purpose put some tiles on this layer.
			> "triggers" : this layer will be filled with all the "_triggers" layer tiles from the main tilemap.
	--]]
	
	tilemap.set_visible(main_tilemap_url, "_triggers", false)
	tilemap.set_visible(triggers_tilemap_url, "bounds", false)
	
	copy_tilemap_layer(main_tilemap_url, "_triggers", triggers_tilemap_url, "triggers")
end

function copy_tilemap_layer(src_tilemap_url, src_tilemap_layer, dest_tilemap_url, dest_tilemap_layer)
	-- IMPORTANT NOTES:
	-- 1. This function only works with already created source and destination tilemap and layers!
	-- 2. It is assumed that both tilemaps share the same tilesource.
	-- 3. Make sure that the source tilemap bounds are at least equal or contained in the destination tilemap!
	--    Otherwise you will get the "Could not set the tile since the supplied tile was out of range." error!

	local bx, by, bw, bh = tilemap.get_bounds(src_tilemap_url)
	for y=by, by+bh-1 do
		for x=bx, bx+bw-1 do
			local id = tilemap.get_tile(src_tilemap_url, src_tilemap_layer, x, y)
			if id ~= 0 then -- avoid nil tiles
				tilemap.set_tile(dest_tilemap_url, dest_tilemap_layer, x, y, id)
			end
		end
	end
end

I hope can be useful for someone! :slightly_smiling_face:

For the other special tiles will use the suggested approach… scan and based on the id of the tile doing stuff! =)

Thank you for all your help! :smile:

1 Like