Closed salvob41 closed 5 years ago
Not sure if signals like that can be connected to actual tile cells. However, as of right now you can add a area2d node as a child of you tilemap, position it over the water area, attach the area/body signal to achieve the same effect.
This also means you can don't use excessive signals, can just use one area2d node. For example, if you had a 32x32 water tile in area size of 288x288, you would have 8 extra signals. when you only really need one
I asked about something similar in Discord. The approach they recommended is:
Alternatively you can also get the tile under your character (using tilemap.world_to_map) and test if it is water or not. Using a water layer can also help, and these don't require to setup any signal connections.
Hi guys, thanks for your feedback. if someone wants to use Tilemaps is because someone wants to speed up the Level design process. He/She wants to try different things, different location of areas, water, spikes, ground, etc. Maybe also in a procedural way.
It is a big work changing everytime also the shape and/or position of the Area2D applied afterwards.
Our current approach is to recognise the tile by its ID (when using Godot Tilemaps) or byt its Object (when using Tiled and the godot-tiled-importer) and create a Area2D on this tile.
But since in Tiled, for instance, there is object layer, can we do something like this in Godot Tilemaps. Recognise a group of tiles and create an Area2D on it (automatically and not by hand after the world is complete). What's your thoughts? Is it possible? Might be useful?
@salvob41 I think that's possible using vnen's tiled importer, and then creating your own post import script. I mean, I don't disagree with your intentions, the easier the better, but there are some things I think you can already do. That should hold you down until the new tileset editor gets more and more polished
@salvob41 Here's some sample code I use in a project of mine to solve this problem. At a high-level, it:
You can clone the repo and try/debug it yourself if you want to see how it's working. This is how I solved the problem of making maps with the tile maps, but getting automatic functionality like collision detection and logic.
@nightblade9 Thank you. Our approach is very similar to yours. You can see here this function does more or less what you're saying:
tile_id
it will iterate all the tiles thanks to the get_used_cells_by_id()
methodThe problem with this approach, though, is that it will generate as many area2D as the number of tiles. Your code does the same for example.
But .. what if I want an area2D big as the extension of all those tiles who are adjacents? Coming back to the previous example of the water: In the level design phase of my game I will create the map with puddles of water, or randomly generate water. It would be cool if it will create a big Area2D where all the tiles are. Something like this
We are starting to implement something like this in a project of ours, here's a sample code.
But this only works for a rectangular shape, high as the cell_size
and large as many adjacent cells they are (along the x axis).
Well, it is something :)
Perform a flood fill algorithm and create a shape using the result of that? (Note that this may not be a good solution for games with dynamic map)
@Zylann I don't know that algorythm but I guess the idea would be to calculate the vertexes of the resulting polygon and then create a shape, right?
Well, that's what I would like to do, but it is a bit complicated and I was wondering if there could be a way to make the Tilemap recognise the "area" thanks to the tiles. In Tiled there are the object-layer that recognise the objects. I was hoping for something like that
Just to clarify, in this example taken from Wikipedia:
From the output I would like three polygons. The top left, the center one and the bottom right.
Although Flood fill algorithm is interesting. It might not be what are we looking for. It is more a Convex Hull problem:
@salvob41 but flood fill could be what gets the points for your hull ;) And Godot has an algorithm to build hulls from that, although it would not be necessarily convex. But again I think just putting water tiles in a separate collision layer would be enough to detect water (with a second tilemap because a tilemap can only have one collision layer), and simpler than trying to force the use of Area2Ds or building static polygons for this situation.
@Zylann that might be doable...
But with Area2Ds I found easier telling the KinematicBody that goes through it what action to make. Sometimes the move_and_slide
gives us a weird behaviour (in our experience at least): When we use the move and slide, the default behaviour seems to be the solidity. With Area2D we can use on_body_entered
and so we can tell the Engine to not stop when "collide" with that Area2D.
With body2D I don't know how to tell that if encounters that specific tile it has to do a specific action (in case of water has to swim, in case of spikes has to die or take damage).
It happens that if a ship collide with a bomb, instead of exploding (as the code states), it just hit it and "slide" around it (maybe because of lagging or FPS).
Another time instead of dying when it makes contact with spikes, it stands on it. I have a picture of this:
There is something I miss, right ?
I may have another solution for this.
The Shape2Ds for each of the cells in the TileMap are managed by the wrapped TileSet resource, right? And each set of Shape2Ds is indexed by its tile ID, yes?
If so, we can just make a generate_area
flag on the TileData. The TileMap node can then maintain child Area2D nodes with a dynamically generated fleet of child CollisionShape2Ds for each Shape2D in the TileSet for the flagged TileDatas. If the TileMap then exposes access to the Area2D by tile ID, then users can simply do...
$TileMap.tile_set.tile_get_collision_area(spikes_id).connect("area_entered", self, "_on_spikes_entered")
Can also expose a method that returns a Dictionary of tile ID to Area2D references (to get the full listing if necessary).
WDYT?
@willnationsdev this will only be useful if you have only one node monitoring these collisions. If you have multiple, they will all be sent the signal when any of them enters an area. You could even script this the same way you can when swapping tiles with scenes.
Having worked with tilemaps in a game where many tiles have effects on the character, to me the best way to handle this still relies on not using signals that much, just checking what the character collides with rather than connecting thousands of signals internally, and exploit collision layers (so you can choose what is solid or not, and it doesn't matter if you collide a tile or something else) because at the end of the day you only need to know you touched water, or something that kills you. Knowing it's a tile doesn't bring much info (there could also be many variants of that tile anyways), and if it's needed that should be obtainable from the hit test and tile metadata. Infortunately tilemaps don't support multiple collision layers AFAIK so that requires a second tilemap for such tiles (which is a good idea in some cases to avoid multiplicating work in tile combinations).
Otherwise... Scene-tiles could bring that workflow an alternative? (Because there have been requests for many node-like features in tilemaps, not just areas)
I would be happy if there was an Area2D option similar to Use Kinematic. If the whole TileMap behaves as an Area2D, it's easy to make a separate layer for that kind of thing.
My specific usecase is to make ladders. My implementation uses Area2D to detect when the player is over a ladder and snaps them to the center of the ladder.
I have just used the script that replaces tiles with scenes as a workaround, but I'm worried that having a separate CollisionShape for every tile can be innefficient. If we could easily extract the collision element that the TileMap generates and use it in an Area2D, that could be a solution.
Seems slightly related to #4454.
There is no way to add an area2D in the Tilemap. Immagine I want to do a platformer where there is water. All the water tiles are supposed to be an Area2D. It would be cool, if I can set up a specific tile as an area2d, So I can move and/or handle the objects enter that Area accordingly.
What do you guys think about that?