Allow RayCast to report collisions through multiple objects #6377
Replies: 5 comments
-
Moving to discussions, as there is no concrete technical implementation provided.
I think documenting the current approach would go a long way 🙂 That said, in other engines, this is usually implemented by performing raycasts iteratively (i.e. perform a second raycast behind the first one if a collision is reported). The same can be achieved in Godot with scripting. |
Beta Was this translation helpful? Give feedback.
-
You can do that in Godot with scripts and a simple loop. Use the |
Beta Was this translation helpful? Give feedback.
-
If anyone comes here for the same problem: In my case, I try to detect if a player walks across one of multiple arbitrary polygons on the ground whose convex hulls are overlapping a lot. Small Ray displacement does not work. Maybe Godot deliberately sets the ray's starting point a little back. In any case, the previous collision is found again even though it shouldn't be. The result is non-deterministic. The probability is good when standing or moving slowly but when moving fast, the iteration doesn't work well. The only working way is what smix8 describes, using the I tried to use TestMove iteratively but this doesn't work, it has no options to exclude collsion objects or choose a collision mask. It might not even find multiple collisions when the polygons are lying in the same plane. |
Beta Was this translation helpful? Give feedback.
-
For future generations: var m_hits: Array[CollisionObject3D]
var m_max_hits: int = 5
func accumulate_hits():
for i in range(m_max_hits):
var collider: CollisionObject3D = get_collider()
if collider:
m_hits.append(collider)
add_exception(collider)
force_raycast_update()
else:
break Then just iterate over accumulated array of hits: func _process(delta):
accumulate_hits()
for hit in m_hits:
if hit is MySuperDuperClass:
print("YYYYYYYAAAAAAAAAAAAAAAAAOOOOOOOOOOOOOOOOOO")
# Don't forget to clear hits and RayCast exceptions
m_hits.clear()
clear_exceptions() |
Beta Was this translation helpful? Give feedback.
-
Here are 2 examples for Godot 4.4: This one CAN'T hit the same object multiple times ## Executes intersect_ray query repeatedly, penetrating through different objects until there are no hits left
## Returns an array of result dictionaries (see PhysicsDirectSpaceState3D.intersect_ray docs)
static func multi_raycast(space_state: PhysicsDirectSpaceState3D, query: PhysicsRayQueryParameters3D, max_iterations: int = 100) -> Array[Dictionary]:
var next_query = query
var hits: Array[Dictionary] = []
var exclusions: Array[RID] = []
var counter := 0
while (next_query != null) and (not counter > max_iterations):
var result = space_state.intersect_ray(next_query)
if !result.is_empty():
hits.append(result.duplicate())
exclusions.append(result.rid)
next_query = null if result.is_empty() else PhysicsRayQueryParameters3D.create(query.from, query.to, query.collision_mask, exclusions)
counter += 1
return hits This one CAN hit the same object multiple times ## Executes intersect_ray query repeatedly, penetrating through different or similar objects until there are no hits left
## Returns an array of result dictionaries (see PhysicsDirectSpaceState3D.intersect_ray docs)
static func marching_raycast(space_state: PhysicsDirectSpaceState3D, query: PhysicsRayQueryParameters3D, max_iterations: int = 100) -> Array[Dictionary]:
var next_query = query
var hits: Array[Dictionary] = []
var dir = (query.to - query.from).normalized()
var counter := 0
while (next_query != null) and (not counter > max_iterations):
var result = space_state.intersect_ray(next_query)
if !result.is_empty(): hits.append(result.duplicate())
next_query = null if result.is_empty() else PhysicsRayQueryParameters3D.create(result.position + (dir * 0.0001), query.to, query.collision_mask)
counter += 1
return hits Example usage: func fire_ray(from: Vector3, to: Vector3, collision_mask: int):
var space_state = get_world_3d().direct_space_state
var query = PhysicsRayQueryParameters3D.create(from, to, collision_mask)
var hits: Array[Dictionary] = multi_raycast(space_state, query)
# var hits: Array[Dictionary] = marching_raycast(space_state, query)
# Do something with hits |
Beta Was this translation helpful? Give feedback.
-
Describe the project you are working on
I'm working on an FPS game where I'm trying to implement bullet penetration, I'm in desperate need for a method that counterparts the RaycastAll() method from Unity. I need multiple hit infos.
Describe the problem or limitation you are having in your project
Raycast only hitting one object and stopping.
Describe the feature / enhancement and how it helps to overcome the problem or limitation
it's pretty self explanatory
Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
You already have ShapeCast that gets multiple hits, perhaps using a shape like a SeparationRayShape3D would do the trick but please, we need something more proper.
If this enhancement will not be used often, can it be worked around with a few lines of script?
the answer is given above
Is there a reason why this should be core and not an add-on in the asset library?
it is a fundamental raycasting option
Beta Was this translation helpful? Give feedback.
All reactions