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.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
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