SimplePath - Pathfinding Module

Can you add a function to make your own path,ie :moveto but with checking if reached?,because well I want to do a tower defense game and my npc stop before reaching the waypooint that i placed,and my code is very long to solve that.Thankyou

Make sure you require the module properly like this:

(From the docs)

--Import the module so you can start using it
local ServerStorage = game:GetService("ServerStorage")
local SimplePath = require(ServerStorage.SimplePath)

--Define npc
local Dummy = workspace.Dummy

-- Define a part called "Goal"
local Goal = workspace.Goal

--Create a new Path using the Dummy
local Path = SimplePath.new(Dummy)

If your NPC stops before reaching the goal, you might want to consider checking for errors using the Path.Error and make sure nothing is blocking the path.

I want to use this on the client, i have a mob that chases a player locally (nobody else sees it, the mob is on the client only)

I am reviewing the code, but is there anything known that would prevent me from keeping the module in ReplicatedStorage and using in on the client?

Not at all. You can use the module completely on the client.

1 Like

Is there a way to specify for humanoid pathfinding what size the humanoid is and what their walk speed is? This is a great module but only really works with normal-sized players at first glance. Please correct me if I’m wrong.

SimplePath does not use a custom pathfinding algorithm. Instead, it uses Roblox’s own PathfindingService. The waypoints generated with SimplePath are exactly what would’ve been generated with PathfindingService. Additionally, like PathfindingService, you can pass in agent parameters to the constructor of the Path for custom humanoids. Take a look at the api for more information on how to use this.

That’s actually very intuitive. Thank you for pointing that out.

Are there any parameters I could change to affect the pathfinding for humanoids with faster or slower walk speeds? After accounting for their sizes in the script, they still struggle sometimes with footing and jumps if they’re really fast or really slow.

EDIT: Here’s some examples of what I mean:
robloxapp-20220113-1659576.wmv (1.0 MB)
robloxapp-20220113-1701430.wmv (1.1 MB)

Nice module really simple way to use path finding! But I have a question by pathfinding with non-humanoids what does it mean and how will it work compared to you know using a humanoid?-Are there more options with the non-humanoid that is using this rather than a humanoid?

I did some quick testing on Studio using a scaled-down rig. To stop the slipping for the rig, I enabled CustomPhysicalProperties and bumped up the density of all the limbs to 100 (ref). I then changed the jump setting to make sure the humanoid can jump at a certain distance and found 43 to be an ideal jump power in my case. Inside the pathfinding script, I passed in the agent parameter WaypointSpacing by increasing it to 7. After all of these changes, this was the result:

robloxapp-20220114-1530501.wmv (364.4 KB)

It’s about tweaking various settings until you get what you want. There isn’t just one way to fix it.

I would suggest you do pathfinding on humanoids instead of non-humanoids. Part of the reason why is because, with humanoids, you have more control. For example, you can easily change properties like speed and jump power directly from the humanoid object. For non-humanoids, you would have to create your own logic to move the model including the handling of jumps, etc.

The issues I’m experiencing with the different size/speed humanoids seem to hinge on the pathfinding apparently calculating waypoints as though they were travelling at the normal speed regardless of what their actual speed is. The smaller, faster humanoid jumps further than it needs to because its walk speed is 32 while the path seems to be calculated for normal speed. It also has issues chasing me like in the second video I posted, where it will slow down to normal walk speed even though it’s supposed to be going fast because of how it’s following the waypoints. The “high density” trick worked kinda well for fixing the first problem but made the second problem even worse (and I don’t like the way it made the bot able to easily push around the player character). The larger, slower humanoid seems to have its pathfinding computed the same way, but since it’s slower than normal, the pathfinding thinks that it can make jumps that it actually can’t (and shouldn’t), so you get that jumping in place that you see in the first video I posted.

It may just be that this specific pathfinding module isn’t suited for my purposes, but if you have any other ideas on how to fix this I’m all ears.

You’re absolutely right. The path is computed using the default settings which the Humanoids use. This is also why it’s encouraged to make use of agent parameters when using a custom Humanoid. You can do nothing in this case except tweaking various settings until you arrive at what you’re looking for. This is also a challenge when using PathfindingService on its own without SimplePath.


The second problem where the Humanoid is unable to reach the character despite its speed is a problem that I addressed before privately with another developer. The problem here is due to the delay between the client and server. Since pathfinding, by default, is done on the server, when your character moves, there’s a delay before the server receives your exact position. The fix is simply to give ownership of the Humanoid to the local client it’s chasing and do pathfinding locally. Again, this problem is unrelated to SimplePath. To test this theory out, just try to constantly move a part to your character’s position on the server. Something like this:

local p = Instance.new("Part", workspace)
p.Size = Vector3.new(1, 1, 1)
p.CanCollide = false
p.Anchored = true

while true do
	local c = workspace:FindFirstChild("V3N0M_Z")
	if c then
		p.CFrame = c.PrimaryPart.CFrame
	end
	task.wait()
end

I’m not entirely sure what you mean by this. SimplePath ensures the Humanoid reaches its goal no matter what. It may even jump on top of its goal if that helps it get closer. If you want the Humanoid to stop a certain distance away from the goal, you should include code that performs distance checks and stops pathfinding as soon as the Humanoid reaches a certain distance to the goal.


The agent parameter AgentCanJump can be set to false to disable jump. Again, the pathfinding behavior of a custom Humanoid is completely up to you. The default settings are just there by default.


In the end, these problems are completely independent of SimplePath. However, even if I modify its code in the future to fix some of the problems somehow, fixing them is still out of the scope of this module. I hope my explanations help with the issues you are facing.

Minor Update:

  • Re-did the website with dark colors
  • Repository now has better version control

I’m newer to scripting and understand a bit about the client v. server distinction and remote events, but I’m unsure how I would do pathfinding locally and “give ownership of the humanoid to the client”. I tried moving most everything to a local script and created the path in a while loop in that script and fired a remote event to the server which had the humanoid run to that point, but when I tested it, the AI stood there and didn’t do anything and there were no errors. Maybe I just need to tinker around with that particular strategy more.

I’m not against the larger humanoid jumping, I just want it to stick to attempting jumps that are actually possible for it to complete. It doesn’t seem to grasp its own jump power or walking speed and behaves like they’re both default. I did try setting AgentCanJump to false and I got entirely new bugs where the bot would stop dead in its tracks when I jump up the stairs and wouldn’t start moving again (even if I jumped down) unless I got really close to it. That might be an issue with PathfindingService in general, though, since I noticed that bug when trying to essentially recreate this module before I knew it existed.

For the speed problem just do a Magnitude check on the waypoint. If there or close-enough; exit the loop and move on to the next. And always aim a bit beyond the next actual waypoint…

Remember when doing a .magnitude check, to strip the Y value from the subtraction by making new Vector3s with the .y value set to 0 as the height of the waypoint may not be the same height, as the Torso, or whatever Part you are subtracting it from. I guess; MoveToFinished could run into this problem too, so set the .y value to the same height as torso of NPC will be, once it gets there, for the input into the MoveToFinished (I don’t know how that Method works…); Or re-align your walls onto the exact voxels of the waypoints (See; bottom)

For the Jump problem, if it’s hard-wired somehow, measure the height of the next node yourself against the Torso height (Only the .y value). If too high;
abandon the path.
Do another Path Find but change the input to pathfind, of the NPC’s .y value lower, like to his feet, so that that the jump is definitely out of range, and the Path tries some other route.

Also you must check the erros returned by pathfind.

The two most important erros are Bad Origin (NPC is too close to some part, so that the Voxel Chunk that it thinks it’s starting from is actually 4 studs over…) so move the Input of the Origin to different places (You can spiral out to different points, by multiples of 4 studs, until you don’t get the error anymore (An empty spot shouldn’t be too far away)).

And Bad Destination Error (I forget the actual error names). Target is inside of a Part or there is no such path there (Two different errors I think)

I just move the target input Vecto3 closer to the NPC, Re-call Pathfind, until you stop getting the Error but maybe you can come-up with something better… Go nuts…

If you never stop getting the errors and have reached the end of your remedies; you are going to have to abandon pathfind, and do something else: Switch to a ray-cast (“Wall-hugger”) AI routine for a second or two; or move some random direction while jumping, or just go straight at player for a second; or some other brilliant idea… If you make some prgress; then try a Pathfind from the new spot… Use your imagination…

You can’t just do nothing…, or maybe you can… Have the NPC start a campfire and warm his hands for a few seconds, or something…

Also, only go to the first 2 or 4 waypoints. Then call another pathfind.

If really close to Player; abandon pathfind, and go straight at him…

You should put an additional; Impeded, check just to make sure that Humanoid is getting somewhere; regardless of no errors being returned…, and do something about it…

I also had a time-out on reaching each waypoint in a reasonable amount of time… Remedy: all of the above, or try the next waypoint or…

You can calibrate all of the numbers for different speed AIs, at the beginning of the Script, by testing a known path for a few steps… I always feel that a newly spawned AI should start inside a building, a bush, or grave, or down some steps, where it looks natural for them to be entering from anyway…

[Lining up your walls, doorways, floors, and steps; so that they sit on the exact same Voxel chunks, which the Pathfind is using lessens the Error returns also… You can find the chunks by drawing 4x4x4 parts in the waypoints returned by pathfind which you should always be doing anyway while debugging. Just like you always draw Rays…]

Remember; computers are stupid: You are the brains of the operation. and must think of everything before it happens.

GL

1 Like

I don’t know if it has been requested before or that it already exists, but I have a feature request: The ability to print what error is happening, currently if anything happens there is no error message, only a non-responding AI, which is, pretty annoying.

But apart from that, it is a great Pathfinding Module!

1 Like

There are more than one ways to see what type of error occurred.

--Simply use the Path.Error to output errors
Path.Error:Connect(print)

--or

--Path:Run() returns false if error occurs
--Error is then stored as Path.LastError
if not Path:Run() then print(Path.LastError) end
2 Likes

I’m getting a “LimitReached” error, what should I do?

1 Like

Just compute the path again using Path:Run().

1 Like