godot_recipes
godot_recipes copied to clipboard
[Discussion] Tilemap: Detecting tiles
Discussion for http://godotrecipes.com/2d/tilemap_collision/
Thanks for the great tutorials and recipes. (They work really well for adults as well ;-) )
After some struggling, i learned that the TileMap::map_to_world resp. world_to_map are misleadingly named. They do not work with global coordinates, but local coordinates of the map. If the map is not scaled nor rotated and the origin at 0/0 (which is not unlikely for a tilemap), things work fine. But when the map is transformed, you actually need to translate the coordinates:
var tile_pos = collision.collider.world_to_map(collision.collider.to_local(position))
I think it would be worth it to mention that in the recipe somewhere.
How about an update to include Tilemap collisions with Area2D, e.g. bullets, etc.
My solution is based on dodgy coding and guessing, but I expect there's a better way ;-)
How about an update to include Tilemap collisions with Area2D
What do you mean? Areas detect TileMaps in the same way they detect any other body.
@cbscribe, what I mean is you don't call move and collide/slide so there are no Colliders, as in on a kinematic you just get the collider then offset the normal. An area2d does not do this so you have to figure out how to project the area2d from its origin to the collision point in the direction it's facing/moving because the body entered doesn't pass the tile cell information.
Well an Area2D does not collide, it overlaps. There is no point of collision, there is a region. This means your area can be touching multiple tiles at once. You have to come up with whatever logic you want to do to deal with that situation. Get the nearest tile to the area's position? Get all overlapping tiles and find the "middle" one? The answer can vary a lot depending on your needs and your setup.
Yes, I know. What I was meaning is there is still a shape that raises the collision signal, exactly the same way your kinematic has a shape for collisions. So in most cases you want to know what tile hit your area 2d first.
On Sun, 6 Jun 2021, 18:46 Chris Bradfield, @.***> wrote:
Well an Area2D does not collide, it overlaps. There is no point of collision, there is a region. This means your area can be touching multiple tiles at once. You have to come up with whatever logic you want to do to deal with that situation. Get the nearest tile to the area's position? Get all overlapping tiles and find the "middle" one? The answer can vary a lot depending on your needs and your setup.
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kidscancode/godot_recipes/issues/19#issuecomment-855435496, or unsubscribe https://github.com/notifications/unsubscribe-auth/ADCERRIFWIH3GHPZ7GRHWGDTROX5TANCNFSM4XAAEJKQ .
thx! it really helped with disappearing tiles!
Hi I just want to contribute with my use case, I'm doing a little breakout clone and I'm using a sphere collider for the ball so I had weird issues with the corners.
# Check collisions with objects
if collision:
# Did we hit a brick
if collision.collider is TileMap:
var brickMap: TileMap = collision.collider
var tile_pos = brickMap.world_to_map(position)
# If any normal component is different than 0 we know the tile is that way
if collision.normal.y > 0:
tile_pos.y -= 1
if collision.normal.y < 0:
tile_pos.y += 1
if collision.normal.x > 0:
tile_pos.x -= 1
if collision.normal.x < 0:
tile_pos.x += 1
# This will remove the tile
brickMap.set_cellv(tile_pos, -1)
My solution just uses the normal to know in which direction from the ball is the tile that I collided with
So there's a pretty irritating issue with the TileMap editor, specifically with the tile ID returned by get_cellv. For starters, this value is not visible in the Inspector, only through the print command or opening up the .tscn in a text editor. The big problem is this: If you remove one of the tiles from a set, that ID is forever prevented from being used, if it is of a number lower than the highest in the set.
So, say you have a tileset with IDs 0, 1, 2, and 3. You then remove the tile with ID 2. If you add a new tile, it will be given ID 4. So now you have a tileset with IDs 0, 1, 3, and 4. If you're using the script in the example to subtract 1 from the tile ID, once it gets to 3, subtracting one from it will remove the tile from the map, instead of going to 1.
The only fix I've found is either creating an entirely new tileset (very carefully), or manually changing the ID values in the .tscn file with a text editor, and then reloading the entire project, and redrawing all the tiles that use the value that was changed. This approach is obviously not viable, especially if you're doing a cascading edit like changing 4->3, 3->2, etc.
There's probably a convoluted workaround using get_tile_ids() and a for loop, but I need to move on from this issue at the moment.
Fantastic, just what I needed! Thanks for the elegant solution.