How would I recompute NPC's path?

  1. What do you want to achieve? Keep it simple and clear!

I am writing an npc that would walk through checkpoints and also handle blocked paths.

  1. What is the issue? Include screenshots / videos if possible!

The problem is that my NPC won’t avoid the obstacles, he simply walks into them.

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?

I tried to use the :ComputeAsync() function again, so I could recompute the path, but the function can only compute the path once, and I also tried to search up for solutions on this forum but I got nothing I wanted. Help appreciated.


local npc = script.Parent
local hum = npc.Humanoid

local rs = game:GetService("RunService")
local ps = game:GetService("PathfindingService")
local path = ps:CreatePath()


local function getpath(dst)

path:ComputeAsync(npc.HumanoidRootPart.Position, dst.Position)
	
return path
end

local function walkto(dst)
	local path = getpath(dst)
	for index, waypoints in pairs(path:GetWaypoints()) do
		hum:MoveTo(waypoints.Position)
		hum.MoveToFinished:Wait()
	end
end

path.Blocked:Connect(function(dst)
	walkto(dst)
end)


while true do
	walkto(workspace.dst1)
	walkto(workspace.dst2)
	walkto(workspace.dst3)
	walkto(workspace.dst4)
end



2 Likes

When new obstacles appear, you need to create a new navigation mesh with ps:CreatePath in your example. You should be doing that in your getpath function as well.

Creating a new navigation mesh in getpath function was a mistake, because my character does not move at all when I run the script. Or maybe I am doing something wrong?

Hey there.

Have you considered using Pathfinding?

I did use pathfinding, what did you mean? :face_with_raised_eyebrow:

1 Like

Oh, I misunderstood. I apologize, I didn’t know your code sample was any longer than the part I had initially seen.

As per your issue, Pathfinding itself is a bit raw, people have made some custom implementations to make your life easier.

I want to make my own scripts though, but I’ll take a look at that

It’s better sometimes to, instead of re-inventing the wheel, use the assets around you. It makes sense when you want to grow, but it doesn’t hurt to take a look at the documentation, how the module was formed, and what ideas can be put into your head upon looking at somebody else’s method. You can basically ‘study’ their methods, and create your own if you are so adamant, however.

In order to recompute the NPC’s path you would need to also do some additional things like:


local myRoot = script.Parent:WaitForChild("HumanoidRootPart")

local myHuman = script.Parent:WaitForChild("Humanoid") 

function getUnstuck()
	myHuman:Move(Vector3.new(math.random(-1,1),0,math.random(-1,1)))
	
	 wait(0.3)
end

function getDistance(target)
	 distance = (myRoot.Position - target.Position).Magnitude
	 return distance
end

function pathToTarget(target)
	local path = game:GetService("PathfindingService"):CreatePath()
	path:ComputeAsync(myRoot.Position,target.Position)
	if path.Status == Enum.PathStatus.Success then
		pathFailCount = 0
		local waypoints = path:GetWaypoints()
		for i,v in ipairs(waypoints) do
			if v.Action == Enum.PathWaypointAction.Jump then
				myHuman.Jump = true
			end
			myHuman:MoveTo(v.Position)
			local moveSuccess = myHuman.MoveToFinished:Wait()
			if not moveSuccess then 
				break
			end
		end
	else
		pathFailCount = pathFailCount + 1
		if pathFailCount > 10 then
			pathFailCount = 0
			getUnstuck()
		end
	end
end

function main()
	local targetDistance = getDistance(target)
	if targetDistance < 1 then
		getUnstuck()
	else
		pathToTarget(target)
	end 
end

while wait(0.1) do
	main()
end
1 Like

Thanks man! I edited the script to make the NPC walk around the checkpoints endlessly and now it works as intended! But there is one small issue: when the path gets blocked, the NPC hits the blocking object, waits for a few seconds and then walks the recomputed path, I dont want him to wait, how would I fix that? (I would mark your post as a solution if you at least give me a hint)

Maybe try to make an obstacle detection function. Try to make something like this: (Note: it will only work if the objects are called “Part”

-- etc

function FindObstacle()
  local distance = 40
  local obstacle = nil
  for i,v in pairs(game.workspace:GetChildren()) do
    local part = v:FindFirstChild("Part")
    if (myRoot.Position - part.Position).magnitude < distance then
      distance = (myRoot.Position - part.Position).magnitude
    end
  end
  return obstacle
end

function escapeObstacle(obstacle)
  myHumanoid:MoveTo(-(Vector3.new((30),0,(30))) * (obstacle.Position))
  while (myRoot.Position - obstacle.Position).magnitude > distance do
		break
	end
end

function main()
        local targetDistance = getDistance(target)
        local object = findObstaclet()
        if object then
          escapeObstacle(object)
        else if targetDistance < 1 then
		getUnstuck()
        else
		pathToTarget(target)
	end 
end

while wait(0.1) do
	main()
end

Not sure if it works though

Looks like I got an error:

Workspace.Dummy.civilianAI:56: attempt to index nil with ‘Position’ (in the FindObstacle function)

Well yeah, this is not operational code, just an example. Even with this one though, you can’t really achieve what you want easily. You would need to do pretty complex things to continually detect objects and recompute paths without waiting.

Oh, I understand. Thanks for the help though.

1 Like