SimplePath - Pathfinding Module

You can refine your script by using the return value of Path:Run(). The return value is false if there is an error in the path computation or otherwise. You can directly handle this in your code. Also, make use of the Path.LastError if required. Furthermore, the module automatically yields between consecutive computations. You don’t need to add a cooldown yourself. I hope your problem is fixed. If not, feel free to contact me further and I can look into it in more detail.

The problem is that I don’t know how to fix the path computations.
I mean, there is a way that the AI can get to the given position, but it just doesn’t do that correctly and makes a wrong path.

PM me the problem and we can look into it in more detail.

I’m trying to recreate the little Humanoid demo provided in the examples, however even though I’ve copied the code verbatim I can’t get it to work. I’ve added a basic R6 dummy to test with but it won’t move at all. Error event always returns TargetUnreachable for some reason no matter where I move the goal. I’m working in a fresh baseplate with no obstacles. I tried both methods, like I mentioned when using the events method the Error event returns TargetUnreachable. When using the loop method the dummy also doesn’t move.

*EDIT: Geez, I’ve figured out why my dummy wasn’t moving. Its root was anchored lol

3 Likes

Lovely module, I’ve had a great time using. Just a tiny problem, stopping the movement of the humanoid with path:Stop() doesn’t really work? I have mine in WaypointReached, stopping the pathfinding after it reaches a certain distance away from the goal, yet it keeps running either way.

EDIT: Exactly 2 seconds after I posted this I realized I left a path:Run() right after stopping. I am sorry. Please keep up the good work with the module!

I’m creating a Right Click to Follow mechanic where you can right click on another player and have an option to follow them. I’ve got it working, I can follow the player and unfollow (by pressing WASD or Space).

I’m storing each players Path and Heartbeat connection in a data table which I use to :Stop() and :Run() existing paths. I also :Stop() and :Disconnect() the connections when a player is not following.

The issue I’m experiencing is, only after a player stops following, their movement becomes kinda choppy. I was wondering if anybody had any ideas as to what’s causing this behavior.

Here’s the code which handles the pathfinding:

rEvt.OnServerEvent:Connect(function(player, action, targetChar)
	if action == "Follow" then
		for _, v in pairs(data) do
			if player == v.Player then
				-- Data already exists, change path goal
				v.Path:Stop()
				v.Path:Run(targetChar.HumanoidRootPart.Position - Vector3.new(0, 0, 5))
				
				player:SetAttribute("IsFollowing", true)
				
				return -- Return to make sure new data is not assigned
			end
		end
		
		-- Assign new data
		local Path = SimplePath.new(player.Character)

		local connection = game:GetService("RunService").Heartbeat:Connect(function()
			Path:Run(targetChar.HumanoidRootPart.Position - Vector3.new(0, 0, 5))
			task.wait()
		end)
		
		player:SetAttribute("IsFollowing", true)

		table.insert(data, {
			["Player"] = player,
			["Path"] = Path,
			["HeartbeatConn"] = connection;
		})
	else
		if player:GetAttribute("IsFollowing") then
			for i, v in pairs(data) do
				if player == v.Player then
					-- Stop path and disable connection
					v.Path:Stop()
					v.HeartbeatConn:Disconnect()
					player:SetAttribute("IsFollowing", nil)
				end
			end
		end
	end
end)

When the character resets the choppiness of the movement goes away.

I’m not sure what could be the root cause but my theory is it’s got to do with how I’m stopping/running the path? Or could it be that this mechanic is not possible with this module because of something internal?

Nice pathfinding code lol
I like it a lot.

this is really cool!
i’m relatively new to scripting, i just wanna ask if there’s a way to make the NPC wander around? would i have to make several waypoints?

PM me what is happening visually so I get a better understanding of the problem.

You would have to get a random position anywhere on the surface of the part and pathfind to that position then repeat.

Edit: You can even place parts around the map and have those as the final targets. You would randomly select one and pathfind to it.

1 Like

awesome, thank you very much, i’ll do the multiple-part waypoints!

Update 2.1

  • Fixed error when Path is destroyed
  • Fixed error if Path is still referenced after being destroyed
1 Like

Hello! how do I correctly use Path:Stop() ?
I assume while pathfinding and running towards to a point I can stop the path and make the agent stop.
for some reason pathfinding still detect as idle?

Not sure I completely understand what you’re asking.

A path can be stopped using Path:Stop() when the dummy is moving and pathfinding.

is there a way to check if a path exists for a character? and a way to get the path for a character without having the variable

1 Like

I get a warning if I try to stop the dummy from moving and pathfinding. for some reason, the idle state is still activated…?

Good day,

Great Module, how would you code multiple destinations such as Part1, Part2 etc and constant loop between theh two parts.

Thanks

From the API for Path:Run():
“This method returns true if path computation was successful. If it returns false , the Path.Error event is fired with a ComputeError . This method automatically yields if the elapsed time between consecutive calls is less than Settings.TIME_VARIANCE .”

Im not entirely sure what you mean by this. What variable do you mean?

1 Like

You’ll get a warning if you attempt to stop pathfinding when the NPC is stopped and in idle state. Only use the Stop method when the Path status is active.

You can do something like this:

local SimplePath = require(game:GetService("ReplicatedStorage").SimplePath)
--Three parts in workspace named: "Part1", "Part2", "Part3"
local Path = SimplePath.new(workspace.Dummy)
while true do
	for i = 1, 3 do
		Path:Run(workspace["Part"..tostring(i)].Position)
		Path.Reached:Wait()
	end
end