What is the best Raycast method? (Performance-wise)

Hello. I have two Raycast methods and I’m wondering which one works best performance-wise. The main objective is to make the ray ignore every part that is invisible or not CanCollide.

The Situation

These Raycast methods will run every time a gun is shot. Say we are firing an automatic weapon with 600 RPM, it would run this method every 0.1 seconds.

Method 1

This method uses a pierce system where if the hit object is transparent or not CanCollide, it fires another Ray at the hit position, respecting the original range given. This method does not use Blacklist Arrays.

local function RayCast(Source, Direction, Range)
	
	local DirectionwMag = Direction * Range
	
	local Result = workspace:Raycast(Source, DirectionwMag)
	
	if not Result then
		
		Result = {Position = Source * DirectionwMag}
		
	elseif Result.Instance.Transparency >= 1 or not Result.Instance.CanCollide then
		
		local Dist = (Result.Position - Source).magnitude
		local newRange = Range - Dist
		
		Result = RayCast(Result.Position, Direction, newRange)
	end
	
	return Result
end

Method 2

This method uses a module that will store every part that the ray should avoid, and will be used as a Blacklist Array.

BlacklistModule

local BL = {}

local function ProcessPart(part)
	if part:IsA("BasePart") then
		
		if part.Transparency >= 1 or not part.CanCollide then
			
			if not table.find(BL, part) then
				table.insert(BL, part)
			end
			
		end
		
	end
end

for _,v in pairs(workspace:GetDescendants()) do
	ProcessPart(v)
end
workspace.DescendantAdded:Connect(ProcessPart)

return BL

MainScript

local BL = require(BlacklistModule)

local function Raycast(Source, Direction, Range)
	
	local param = RaycastParams.new()
	param.FilterType = Enum.RaycastFilterType.Blacklist
	param.FilterDescendantsInstances = BL
	
	local DirectionwMag = Direction * Range
	
	local Result = workspace:Raycast(Source, DirectionwMag, param)
	if not Result then
		Result = {Position = Source * DirectionwMag}
	end
	
	return Result
end

Again I’m asking which method is more better in terms of performance. Personally I think Method 2 would produce a lot of background lag while Method 1 may lag too if there are too many parts in the way of one direction.

  • Method 1
  • Method 2

0 voters

1 Like

I dont think it matters as the both are just different methods of detecting whether to register the hit and are basically the same performance wise

1 Like

A rays performance is measured by the length of the ray, unfortunately, we don’t know how Roblox internally handles the ray for blacklist and whitelist. We can probably assume the more objects whitelisted/blacklisted the more expensive (considering we provide an array of objects, not a dictionary)

1 Like

Neither of these is optimal. Method 1, as written, will not handle all the cases that Method 2 will. It will not correctly deal with a hit at a position where more than one parts’ surfaces intersect. That is to say, Method 1 is not a valid piercing raycast. You can easily test this just by duplicating a block in place, and noticing only one can be detected (and which block is hit can depend on order they replicate, O_o)

Method 2 will work as intended, but lacks the distance-shortening optimization of Method 1.

IMO, the best way would be to use Method 2, with the black list, but combine it with the path-shortening idea from Method 1, only you can’t use the exact hit position, you have to “rewind” a short distance along the ray path to ensure that you correctly detect multiple parts overlapping.

2 Likes