-
What do you want to achieve?
I’m working on an AI for a game and I want to have a functioning pathfinding system that can track down potentially moving players. -
What is the issue?
When tracking down a stationary target, the AI is perfectly capable of reaching them in almost all scenarios that I’ve tested. However, when trying to track down a moving target or a target that has recently moved, the AI frequently will stop in place or walk into walls, and sometimes cannot find a path despite a path being available, resulting in a NoPath status. -
What solutions have you tried so far?
I’ve tried adjusting the radius, height, and spacing of the path, and I’ve made numerous attempts to add or rewrite the checks for when it needs to recompute a path, but to no avail.
local PFS = game:GetService("PathfindingService")
local P = game:GetService("Players")
local root = script.Parent:WaitForChild("HumanoidRootPart")
local humanoid = script.Parent:WaitForChild("Humanoid")
local path = PFS:CreatePath({
AgentRadius = 2,
AgentHeight = 6,
WaypointSpacing = 6,
AgentCanJump = true,
Costs = {
Water = 20,
Mud = 5
}
})
local waypoints
local blockedConnection
local params = RaycastParams.new()
function Raycast(a,b)
local A = (a-b)
local Dist = A.Magnitude
local Dir = A.Unit
local ray = workspace:Raycast(a,(Dist)*Dir,params)
return ray
end
function GeneratePath(target)
local destination = target.PrimaryPart.Position
local success, errorMessage = pcall(function()
path:ComputeAsync(root.Position, destination)
end)
print(path.Status)
if success and path.Status == Enum.PathStatus.Success then
-- Get the path waypoints
waypoints = path:GetWaypoints()
local waypointIndex = 0
local canContinue = true
for i,v in pairs(waypoints) do
if i == 1 then continue end
destination = target.PrimaryPart.Position
local total = 0
for a,b in pairs(waypoints) do
local dist = (destination-b.Position).Magnitude
if dist > 5 then
total += 1
end
end
if total >= #waypoints then
canContinue = false
coroutine.wrap(function()
GeneratePath(target)
end)()
break
end
if canContinue then
waypointIndex = i
humanoid:MoveTo(v.Position)
if v.Action == Enum.PathWaypointAction.Jump then
humanoid.Jump = true
end
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
if blockedWaypointIndex >= waypointIndex then
blockedConnection:Disconnect()
canContinue = false
GeneratePath(target)
end
end)
local jHeight = humanoid.JumpPower^2 / (2*workspace.Gravity)
local heightVector = Vector3.new(0,script.Parent:GetExtentsSize().Y,0)
local jHeightVector = Vector3.new(0,script.Parent:GetExtentsSize().Y/2+jHeight,0)
params.FilterDescendantsInstances = {script.Parent,target}
for a=1,3 do
if waypoints[i+a] ~= nil then
local ray = Raycast(waypoints[i+a-1].Position,waypoints[i+a].Position)
local ray2 = Raycast(waypoints[i+a-1].Position+heightVector,waypoints[i+a].Position+heightVector)
local ray3 = Raycast(waypoints[i+a-1].Position+jHeightVector,waypoints[i+a].Position+jHeightVector)
if ray and ray2 and ray3 then
canContinue = false
coroutine.wrap(function()
GeneratePath(target)
end)()
break
end
end
end
humanoid.MoveToFinished:Wait()
else
break
end
end
end
end
I apologise for the messy code, the target argument is just an NPC or character.
If it helps, here is a screenshot of the maze that I’m using to test the pathfinding.