Raycast cone distance checker always picks the 'central' raycast

I have this really simple function that emits some raycasts in the direction of the agent, and with the length of safe distance (for the enemy i was testing, it was 30).

The function is meant to return the longest raycast, which it does very well, but one thing i’m not sure works correctly is the fact that the logic always returns the central raycast.


This isn’t exactly a major issue, but it is something i’d like to fix.

local retreatConeAngle = math.rad(120)
local retreatConeCenter = retreatConeAngle / 2
local retreatConeStep = math.rad(2)

function navigation.GetBestRetreatPosition(agent: Model, retreatFrom: BasePart, safeDistance: number): Vector3
	local agentRoot = agent.PrimaryPart
	
	local agentOrigin = agentRoot.Position
	local targetOrigin = retreatFrom.Position
	
	local directionToAgent = (agentOrigin - targetOrigin).Unit
	local parameters = RaycastParams.new()
	
	parameters.FilterDescendantsInstances = {agent}
	parameters.FilterType = Enum.RaycastFilterType.Exclude
	
	local bestPosition = agentOrigin
	local bestDistance = -math.huge
	local bestDebugPart = nil
	
	for angle = -retreatConeCenter, retreatConeCenter, retreatConeStep do
		local rotatedDirection = CFrame.fromAxisAngle(Vector3.yAxis, angle) * directionToAgent
		rotatedDirection = Vector3.new(rotatedDirection.X, 0, rotatedDirection.Z).Unit
		
		local finalizedDirection = rotatedDirection * safeDistance
		local result = workspace:Raycast(agentOrigin, finalizedDirection, parameters)
		
		local candidatePosition = nil
		if result then
			candidatePosition = result.Position
		else
			candidatePosition = agentOrigin + finalizedDirection
		end
		
		local midpoint = (agentOrigin + candidatePosition) / 2
		local partLength = (candidatePosition - agentOrigin).Magnitude
		local debugPart = CreateDebugRaycast(midpoint, partLength, candidatePosition)
		
		local distance = (candidatePosition - targetOrigin).Magnitude
		if distance > bestDistance then
			bestDistance = distance
			bestPosition = candidatePosition
			bestDebugPart = debugPart
		end
	end
	
	if bestDebugPart then
		bestDebugPart.Color = Color3.fromRGB(161, 255, 146)
		bestDebugPart.Transparency = 0.25
	end
	
	return bestPosition
end

I haven’t read your code, and I haven’t done any trigonometry in a hot minute, however, as long as the diagonal raycast is never obstructed, then that one will always be longest.
In the roughly mouse-drawn image below, the thicker blue line represents the digonal raycast (center)

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.