How to find a position that's not visible to another position?

  1. What do you want to achieve? I want to make an npc that retreats to a safe positions that’s not visible to the damage source’s position.

  2. What is the issue? Not a lot of times, but the NPC just moves to a position where the enemy can still see it and attack it.

  3. What solutions have you tried so far? I tried raycasting but it doesn’t work some of the times.

function bot.Retreat(botID,damagePos,enemyModel)
	local botModel = returnBotModel(botID)
	local currentBot = bot.returnBot(botID)
	
	if currentBot then
		currentBot.Status = "Retreating"
		local res

		if botModel then
			local retreatPos
			local foundSpot = false
			
			while foundSpot == false do
				task.wait(0.001)
				local hidePos = botModel.PrimaryPart.Position + Vector3.new(math.random(-25,25),0,math.random(-25,25))
				local dir = CFrame.lookAt(damagePos,hidePos).LookVector
				local rayParams = RaycastParams.new()
				rayParams.FilterType = Enum.RaycastFilterType.Exclude
				rayParams.FilterDescendantsInstances = {enemyModel}
				local result = workspace:Raycast(damagePos,dir * 9999,rayParams)
				
				if result ~= nil and result.Instance ~= nil and result.Instance.Parent and result.Instance.Parent ~= botModel then
					retreatPos = hidePos
					foundSpot = true
					res = result
				end
			end
			local path = pathFinding:CreatePath()

			local hum = botModel:FindFirstChildOfClass("Humanoid")

			path:ComputeAsync(botModel.PrimaryPart.Position,retreatPos)
			local waypoints = path:GetWaypoints()

			for index,waypoint in pairs(waypoints) do
				print(waypoint)
				hum:MoveTo(waypoint.Position)
				hum.MoveToFinished:Wait()
			end
			
			currentBot.Status = "Default"
		end
	end
end

Any help would be appreciated!

2 Likes

If you have this for a story game and not a map that is constantly changing/being moved around, you might want to make preset cover spots, then raycast to see if those provide cover, and move to them.

1 Like

I’m making this for a first person shooter, but I guess that works. How should I know, what’s the most optimal hiding spot out of all available? Because sometimes the npc has to get really close to the player in order to avoid an obstacle.

1 Like

It’s your map. If that’s the approach you’re ok with taking, you can try that. If not, send a video of your script in action and I may help further

1 Like


Here, sometimes it works fine but in other times it moves to a position where I have clear vision of it and can perfectly attack it.
(the red cube is the damage source’s position, the green cube is the retreatPos from the script)

The Code is working as intended, you should run some code to raycast multiple times to make sure they cannot get spotted by the player after a small movement (get them to move into deeper cover)
I would help write code, but I am currently on a mobile device, however, yes, your code IS working.

1 Like

Alright, I’ll try to do that. Thanks for the reply!

No problem, feel free to let me know if you have issues writing the code.

My code still doesn’t work as intended, what a shame.
image

while foundSpot == false do
				task.wait(0.001)
				local hidePos = botModel.PrimaryPart.Position + Vector3.new(math.random(-25,25),0,math.random(-25,25))
				local dir = CFrame.lookAt(damagePos,hidePos).LookVector
				local rayParams = RaycastParams.new()
				rayParams.FilterType = Enum.RaycastFilterType.Exclude
				rayParams.FilterDescendantsInstances = {enemyModel}
				local result = workspace:Raycast(damagePos,dir * 9999,rayParams)
				
				if result ~= nil and result.Instance ~= nil and result.Instance.Parent and result.Instance.Parent ~= botModel then
					
					for i = 1,3 do
						local newDir = CFrame.lookAt(damagePos,hidePos).LookVector
						local result1 = workspace:Raycast(damagePos,newDir * 9999,rayParams)
						if result1 ~= nil and result1.Instance ~= nil and result1.Instance.Parent and result1.Instance.Parent ~= botModel then
							if i == 3 then
								foundSpot = true
								res = result
								retreatPos = hidePos
								print("found hide spot")
							else
								continue
							end
						else
							foundSpot = false
						end
					end
				else
					foundSpot = false
				end
			end

(NPC still walks to a point where it’s clearly visible even after raycasting 4 times, the green part being the position where it runs away)

Try reducing the distance for those raycasts?

image

image

set the distance to 100 and nope, not working lmao

@LamentedStar maybe I’ll just switch to premade covers?

You should if you’re considering keeping a relatively static map. How I would recommend doing it was creating little “Cover Zones” Across the map and checking if they are clear by doing Workspace:GetPartsInPart(). If this cover spot is out of sight from the player, they will pathfind over

Oh, thanks to your post, I realized a solution of my own. Since it’s a first person shooter, I can make it find a position, then make the client check if the position is actually covered using :GetPartsObscuringTarget() method of the Camera.

Awesome! Good luck with that, dude!

thanks bro, you helped me a lot

1 Like

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