Open edddieee opened 3 years ago
The raycast hit position is not accurate enough to retrieve the corresponding cell by position, because the result is exactly at the edge between two cells, and mathematical approximations will give you inconsistent results.
There's currently no easy way to get the proper cell that was hit by the raycast though, so that needs to be fixed in the GridMap
API. Since it's already possible to get the hit shape
from the raycast result (it's the internal shape index from the physics server, so it's not very useful at the moment), an easy way would be to add a function to GridMap
like shape_index_to_map()
in order to get the map coordinates from a shape. It can be useful for collision information too.
As a workaround, in your case you can add a little bit of extra distance to your raycast hit position to make sure it's inside the box when a hit occurs, and it will give you consistent results:
var space_state = get_world().direct_space_state
var start = camera.project_ray_origin(crosshair.position)
var ray_dir = camera.project_ray_normal(crosshair.position)
var end = start + ray_dir * ray_length
var result = space_state.intersect_ray(start, end, [self.get_rid()])
if result and Input.is_action_just_pressed("ui_accept"):
var hit_pos = result.position
hit_pos += ray_dir * 0.001 # add some extra distance to ensure we're inside the hit cell
print(str(hit_pos) + " # WORLD SPACE")
print(str(hit_pos / 2) + " # CELL COORDS")
print(str((hit_pos / 2).floor()) + " # CELL COORDS with floor()s")
print(str(grid_map.world_to_map(hit_pos)) + " # world_to_map()")
print("====================")
Hey @pouleyKetchoupp , thanks for all information! The workaround works very well!
With Godot 4.1.2 you can actually get the normal vector of the hit position to calculate which cell was hit and which cell was in front of that cell. Like this:
func _input(event: InputEvent):
var crosshair_position = camera.get_window().size / 2 # cursor at the center, because I'm using MOUSE_MODE_CAPTURED
var ray_start = camera.project_ray_origin(crosshair_position)
var ray_dir = camera.project_ray_normal(crosshair_position)
var ray_end = ray_start + ray_dir * RAY_LENGTH
var intersect_ray_params = PhysicsRayQueryParameters3D.create(ray_start, ray_end, 0xFFFFFFFF, [get_rid()])
var result = get_world_3d().direct_space_state.intersect_ray(intersect_ray_params)
if not result or not is_instance_of(result.collider, GridMap):
return
var grid_map = (result.collider as GridMap)
var normal_offset = grid_map.cell_size / 2 * result.normal
# the cell that has been hit
var cell_world_position: Vector3 = result.position - normal_offset
var cell_position = grid_map.local_to_map(cell_world_position)
# the "empty" cell in front of the cell being hit
var empty_world_position: Vector3 = result.position + normal_offset
var empty_position = grid_map.local_to_map(empty_world_position)
Godot version:
3.2.3-stable_x11.64 (Also tested in 3.1.2-stable_x11.64)
OS/device including version:
Manjaro 20.2.1 Nibia
Issue description:
The
world_to_map()
sometimes return inconsistent values when using theintersect_ray()
method. See the output from the image below:Looking the z axis from output you will see an inconsistent values between the first and second image. I also tried to reproduce the
world_to_map
method, dividing theresult.position
by thecell_size
and then using thefloor()
method, but in both cases I get the same inconsistent value.Steps to reproduce:
result
from the ray.result.position
to theworld_to_map()
.Minimal reproduction project:
GridMapRaycastBug.zip