As per title, I want to perform a raycast and get all the collisions from the start to the end of the ray rather than just the first. I tought of performing the raycast multiple times using the last collision as the new start point, and adding the collider to the list of exceptions, but that seems like it’d be pretty slow.
So is there a way to get all the collisions without performing multiple raycasts?
I don’t think so, I do it the way you described it.
Shape casts return an array of all the objects they intersect, but I don’t know if a single shape cast is cheaper / faster than the multiple ray casts method.
I had a similar situation in my project, and finally I used an Area2D to detect the collisions.
This is better than using a Raycast2D because:
Areas emit signals when something enters, hence you can use signals instead of _process (better performance)
Areas have the .get_overlapping_areas/bodies method, which allows you keep track of all the collisions. In my case I iterate over the overlapping areas and depending of the position of the area I can execute different functions.
Yeah, shapes can collide at multiple points so it can’t give you a single collision point.
Then I think you’re left with the multiple ray casts method. I do something like this:
func get_entities_in_line_of_sight(from: Vector3, to: Vector3, exclude: Array[RID] = []) -> Array[Node3D]:
const MAX_COLLISIONS: int = 20
var entities: Array[Node3D] = []
var world_state: PhysicsDirectSpaceState3D = get_world_3d().get_direct_space_state()
for i in MAX_COLLISIONS:
var query := PhysicsRayQueryParameters3D.create(from, to)
query.set_exclude(exclude)
var result: Dictionary = world_state.intersect_ray(query)
if result:
entities.append(result.collider)
exclude.append(result.rid)
from = result.position
else:
break
return entities
Thanks, I was using intersect_shape, which does not give collision points, guess I should have used Shapecast. Is there any way to check which object a collision point “belongs” to, in case the shape intersects multiple objects?
Yes, just use the index to get all the info about the collision
@onready var shapecast3d: ShapeCast3D = $the_node_path_for_you_shape_node
func _physics_process(delta) -> void:
for i in range(0, shapecast3d.get_collision_count()):
var collision_object = shapecast3d.get_collider(i)
var collision_point = shapecast3d.get_collision_point(i)
var collision_normal = shapecast3d.get_collision_normal(i)
Check the link from my last comment to get all the methods that you can use