How to cast rays through blocks that have cancollide set to false

Could you perhaps explain how to do the third method? Sorry, again I’m not the best at scripting (especially raycasting.)

1 Like

Something like this should work, thought I didn’t test it thoroughly:

local function RaycastWithACondition(condition, origin, direction, raycastParams) -- condition is a function which returns true or false
	local raycastResult = workspace:Raycast(origin, direction, raycastParams)

	if raycastResult == nil or condition(raycastResult.Instance) then -- this is to ensure we dont call condition(nil)
		return raycastResult -- returns nil or RaycastResult
	end

	-- if the condition didnt pass

	local intersection = raycastResult.Position

	direction = direction - (intersection - origin) -- previous direction reduced by the distance traveled from the previous origin to the intersection
	origin = intersection -- the intersection is the new origin of the next ray

	return RaycastWithACondition(condition, origin, direction, raycastParams) -- recursion, back to the top of the function with new origin and direction
end

I implemented the above one with recursion, you can also use a while loop:

local function RaycastWithACondition(condition, origin, direction, raycastParams) -- condition is a function which returns true or false
	while true do
		local raycastResult = workspace:Raycast(origin, direction, raycastParams)

		if raycastResult == nil or condition(raycastResult.Instance) then -- this is to ensure we dont call condition(nil)
			return raycastResult -- returns nil or RaycastResult
		end

		-- if the condition didnt pass

		local intersection = raycastResult.Position

		direction = direction - (intersection - origin) -- previous direction reduced by the distance traveled from the previous origin to the intersection
		origin = intersection -- the intersection is the new origin of the next ray
	end
end

You should probably put this in some module script and return it (or put it in a table and return the table), so any script can access it.

Here is an example of the condition function:

local function condition(instance)
    return (instance.Transparency < 1 and instance.CanCollide) -- true if a part's Transparency is below 1 and CanCollide is true, otherwise false
end

Some implementation notes:

  1. I tested it and it seems like if you cast a ray that originates from the intersection of the previous ray and a part, it won’t hit the same part again. Basically, a ray that starts from inside a part and goes through it, doesn’t intersect with it. This might not be true for some kinds of unions/meshes with complicated geometries, but the function should still work. This way it’s simpler and we don’t have to mess with tables/Blacklists. From what I know, RaycastParams.FilterDescendantsInstances copies any table you set it to, so it would essentially be creating a new table every time, which wouldn’t be good.
  2. I also tested for the edge case of the ray hitting a part which doesn’t pass the condition at exactly origin + direction. I couldn’t get it to happen. In that case, it would attempt a useless raycast with a direction vector of Vector3.new(0, 0, 0). It would still correctly return a nil, but we could technically prevent the extra workspace.Raycast call by checking if direction == Vector3.new() or if direction.Magnitude == 0. I found this check unnecessary, since it seems like rays don’t detect an intersection at the end of the ray. I tested this by casting a ray with an origin of Vector3.new(0, 0, 0) and a direction of Vector3.new(0, 1, 0). It intersected a part above it at Vector3.new(0, 0.5, 0). Then I tested the same scenario with a direction of Vector3.new(0, 0.5, 0) and there was no intersection.
4 Likes

Just coming back I would use a while loop because of callstack overflow.

Hey people, forgot to put a solution on this. Roblox now has a new property called ‘CanQuery’ which manages this exact thing. Therefore, this thread is now deprecated. Sorry everyone!

https://developer.roblox.com/en-us/api-reference/property/BasePart/CanQuery

3 Likes