Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tilemap world_to_map() does not get the correct tile in combination with Raycast2D #35344

Open
Tracked by #39876
golddotasksquestions opened this issue Jan 20, 2020 · 6 comments

Comments

@golddotasksquestions
Copy link

golddotasksquestions commented Jan 20, 2020

Godot version: 3.1 stable, 3.2 rc1

OS/device including version: Win7

Issue description:
When casting a ray onto a tilemap to detect a tile, I would expect for world_to_map() to return the Tile directly behind the ray collision point, in the direction of the ray, not on the right and below the collision point.
But since get_collision_point() returns a point exactly between the two tiles and world_to_map() returns the tile right and below the given point, the wrong tile is returned from world_to_map():

tileset_mining

Steps to reproduce:

extends RayCast2D

func _physics_process(delta):
	if Input.is_action_just_pressed("Mine_Left") and is_colliding():
		var target = get_collider()
		if target.is_class("TileMap"):
			var point = get_collision_point()
			var map_point = target.world_to_map(point)
			target.set_cellv(map_point, 0, false, true)

Minimal reproduction project:
Tileset_Mining.zip

@groud
Copy link
Member

groud commented Jan 20, 2020

The behavior is kind of expected then. Instead of using the collision point, which is at the border of the tile, you should probably use the tip of your raycast instead.

@Xrayez
Copy link
Contributor

Xrayez commented Jan 20, 2020

I guess you could also do:

var safe_margin = 1.0 # increase this if doesn't work
var point = get_collision_point() - get_collision_normal() * safe_margin

That way you can kind of prevent these edge-cases where floating point math is not your friend.

Might be also related to something similar issue as in #26615.

@golddotasksquestions
Copy link
Author

@Xrayez Thank you so much, this works great!
If that's the expected way to solve this problem, it probably should be documented somewhere.

@Xrayez
Copy link
Contributor

Xrayez commented Jan 21, 2020

@golddotasksquestions maybe, yet this specific problem doesn't seem to pertain to tilemap or raycast in isolation so not sure if this can be properly documented, at least in the class reference. I find it difficult to come up with proper wording to describe this, so it does feel like a workaround currently.

If you re-run the raycast pointing from the origin to the collision point again exactly, is_colliding should return true. I know that because I do quite similar technique for a use case where I want to prevent continuous raycast detection, the only difference is that - becomes +:

var point = get_collision_point() + get_collision_normal()

It means that the returned collision point cannot be blamed for inaccurate results. So yeah it does smell like world_to_map() is not precise enough.

I've also looked at the source code for this method now, and stumbled upon this issue: #23250. So the proposed fix is indeed a hack currently. Your use case was described by @Zylann at #23250 (comment).

@golddotasksquestions
Copy link
Author

golddotasksquestions commented Jan 22, 2020

It means that the returned collision point cannot be blamed for inaccurate results.

Yes, exactly. In the Minimal project I moved the ColorRect to the collision point position to verify this. It's hundred percent accurate.

I've also skimmed over #23250 before writing this, but I did not understood the "hack" and assumed because it was closed, 23250 was about something else.

Maybe either Raycast2D or wold_to_map needs a bias argument for cases like this?
Personally I'm fine with using the collision normal. But I don't find coming to that conclusion intuitive at all. More like detective work.

@nikhilCad
Copy link

@Xrayez thanks for the fix above, you just saved my life!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants