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.
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.
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
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.
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.
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.
My code still doesn’t work as intended, what a shame.
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)
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.