How to yield until a pathfinding function returns a value?

Good afternoon.
I want to create a sequence of actions to be performed by an NPC script.
However, the included pathfinding service doesn’t provide a way to wait until the agent reaches its goal.
My idea was to make my pathfinding function return a value and wait for it within the NPC’s script. But I think a task.wait() loop isn’t adequate, and I don’t understand coroutines yet.

Here is the code I have so far:

NPC script
local ServerStorage = game:GetService('ServerStorage')
local PathModule = require(ServerStorage.PathModule)
local character = script.Parent
local brick = workspace.DestinyPart.Position

PathModule.goTo(character, brick)
-- Yield code (???)
print("Done!")
Pathfinding module
local PathModule = {}

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

local waypoints
local nextWaypointIndex
local reachedConnection
local blockedConnection

function PathModule.goTo(character, destination)
	local humanoid = character.Humanoid
	local success, errorMessage = pcall(function()
		path:ComputeAsync(character.PrimaryPart.Position, destination)
	end)
	
	if success and path.Status == Enum.PathStatus.Success then
		waypoints = path:GetWaypoints()
		blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
			if blockedWaypointIndex >= nextWaypointIndex then
				blockedConnection:Disconnect()
				PathModule.followPath(character, destination)
			end
		end)
		
		if not reachedConnection then
			reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
				if reached and nextWaypointIndex < #waypoints then
					nextWaypointIndex += 1
					humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
				else
					reachedConnection:Disconnect()
					blockedConnection:Disconnect()
					--return true
				end
			end)
		end
		
		nextWaypointIndex = 2
		humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
	else
		warn("Path doesn't compute.", errorMessage)
	end
end

return PathModule

I would like someone to point me in the best direction.
Thanks for your attention!

1 Like

Have you tried using the MoveToFinished:Wait() after issuing the MoveTo() command? It’s not perfect but it does work.

There are custom alternatives, such as:

-- MOVETO TIMEOUT FUNCTION
local function waitUntilTimeout(event, timeout)
	local signal = RbxScriptSignal.CreateSignal()
	local conn = nil
	conn = event:Connect(function(...)
		conn:Disconnect()
		signal:fire(...)
	end)
	delay(timeout, function()
		if (conn ~= nil) then
			conn:Disconnect()
			conn = nil
			signal:fire(nil)
		end
	end)
	return signal:wait()
end

-- Then in your script, issue the MoveTo(), then start the timeout func
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
-- Check for Move Timeout					
if waitUntilTimeout(humanoid.MoveToFinished, movementTimeout) == nil then
	humanoid:MoveTo(keeper.PrimaryPart.Position) -- cancel any pending movement
	break
end
1 Like

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