I just tested the NPC again today and it works completely fine again, I don’t know why it was bugged yesterday causing the crash, strange…
Hello! I’m lazy but at the beginning of the topic you left a guide on how to implement this module, but I saw that the module has several updates ; Should I use the guide you left at the beginning? I really need to implement it in my game.
How does this module handle multiple NPCs running at once? Haven’t tried it out yet but I plan to make a wave based enemy system with a multiple enemies (5 - 25) and I was curious how this module will hold up when it comes to performance.
If you really need to implement it, don’t be lazy. Read the documentation
Im having problems with multiple enemies using pathfinding, they’re moving towards the closest player but they keep walking back and then move a little towards the player and repeating. I’m writing it exactly like the documentation I don’t understand why its doing this. Btw it only does this when multiple enemies are spawned in but if there is only one it works perfectly.
--Import the module so you can start using it
local ServerStorage = game:GetService("ServerStorage")
local SimplePath = require(ServerStorage.SimplePath)
--Define npc
local dummy = script.Parent
--Create a new Path using the Dummy
local Path = SimplePath.new(dummy)
--Helps to visualize the path
Path.Visualize = false
local isDestroyed = false
local maxDistance = 100000
function getClosestPlayer()
local nearestPlayer, nearestDistance
for _, player in pairs(game.Players:GetPlayers()) do
local character = player.Character
local distance = player:DistanceFromCharacter(dummy.HumanoidRootPart.Position)
if not character or
distance > maxDistance or
(nearestDistance and distance >= nearestDistance)
then
continue
end
nearestDistance = distance
nearestPlayer = player
end
if nearestPlayer.Character.HumanoidRootPart then
return nearestPlayer.Character.HumanoidRootPart
end
end
local run = script:WaitForChild("run")
local humanoid = dummy:WaitForChild("Humanoid")
local runAnimation = humanoid:LoadAnimation(run)
while true do
Path:Run(getClosestPlayer())
end
Having an issue where when the Humanoid dies, the rig has a chance to disappear. I have added a ragdoll on death but when removing it still does the same thing.
Has worked well for my game with bot waves, but your surrounding logic needs to minimize how often it tries to recalc routes if things get stuck, etc
Edit: I should note that I manage all the npc from a single script and run their individual logic on a coroutine thread
I manage it from a single script as well. Do you mind sharing how I could optimize recalculating paths when it comes to enemies in waves, as that’s what I’m going for as well?
Keep in my mind, the NPC’s only disappear rarely when normally walking, but almost 80% of the time on death. Not sure if this has to do anything with recalc routes but I’m fairly new to this module.
function class:Start()
local rig : Model = self.Rig
local humanoid : Humanoid = self.Rig.Humanoid
local radius = 20
local player = nil
local isFollowing = false
local followRange = 80 -- Adjust the follow range as needed
local nearestPlayer
local Path = simplePath.new(rig)
Path.Visualize = true
self.Walk:Play()
humanoid.StateChanged:Connect(function(old, new)
if new == Enum.HumanoidStateType.Dead then
self.Idle:Stop()
self.Walk:Stop()
Path:Destroy()
end
end)
local function followPlayer()
if rig.Humanoid.Health > 0 then
nearestPlayer = findNearestPlayer(followRange, rig.PrimaryPart)
if nearestPlayer then
isFollowing = true
--Cancel Current Path
if Path.StatusType.Active == true then
Path:Stop()
end
Path:Run(nearestPlayer.PrimaryPart.Position)
else
isFollowing = false
end
end
end
local function Wander()
--Cancel Current Path
if Path.StatusType.Active == true then
Path:Stop()
end
self.Walk:Stop()
self.Idle:Play()
wait(math.random(2, 5))
self.Idle:Stop()
self.Walk:Play()
Path:Run(rig.PrimaryPart.Position + Vector3.new(math.random(-radius, radius), 0 , math.random(-radius, radius)))
end
-- Check for nearby players periodically
task.spawn(function()
while true do
if not isFollowing then
followPlayer()
end
wait() \
end
end)
-- Wandering
Path.Reached:Connect(function()
if not isFollowing then
Wander()
else
if not self.Walk.IsPlaying then
self.Idle:Stop()
self.Walk:Play()
end
Path:Run(nearestPlayer.PrimaryPart.Position)
end
end)
Path.WaypointReached:Connect(function()
if isFollowing then
if not self.Walk.IsPlaying then
self.Idle:Stop()
self.Walk:Play()
end
Path:Run(nearestPlayer.PrimaryPart.Position)
end
end)
Path.Error:Connect(function(errorType)
-- warn(errorType)
if isFollowing then
if not self.Walk.IsPlaying then
self.Idle:Stop()
self.Walk:Play()
end
Path:Run(nearestPlayer.PrimaryPart.Position)
else
Wander()
end
end)
--Dummy knows to compute path again if something blocks the path
Path.Blocked:Connect(function()
if isFollowing then
if not self.Walk.IsPlaying then
self.Idle:Stop()
self.Walk:Play()
end
Path:Run(nearestPlayer.PrimaryPart.Position)
else
if Path.StatusType.Active == true then
Path:Stop()
end
Path:Run(rig.PrimaryPart.Position + Vector3.new(math.random(-radius, radius), 0, math.random(-radius, radius)))
end
end)
-- Start wandering initially
Path:Run(rig.PrimaryPart.Position + Vector3.new(math.random(-radius, radius), 0, math.random(-radius, radius)))
end
Here is my currently enemy code, not sure how I’m able to fully optimize it but help would be apprecitaed
please help, wth do i do when this happens?
ServerStorage.SimplePath:327: attempt to perform arithmetic (sub) on number and nil
Same here. I set the NPC’s WalkSpeed to 18 and it causes the NPC to stutter which makes it slower. Have you found a solution yet?
I dont know why, but after Path:Destroy()
(i think), its still gives an error like:
attempt to index nil with 'Status'
Also experiencing this issue. It seems to occur once you’ve destroyed a path once and now want to create a new one.
When I have multiple npcs, and I use Path:Destroy(), it says attempt to call missing method Destroy() on table
Really good module! Easy to use, and working perfectly!
I don’t know how this module does it, but it was an absolute lifesaver with being able to cancel previous paths
i love you glorious grayzcale
does simplepath have a timeout when getting stuck?
Why does my client side code does not work? Its in starterplayerscripts, it should work
local SimplePath = require(game.ReplicatedStorage:WaitForChild("SimplePath"))
local events = {
Create = game.ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("CreatePath");
Start = game.ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("StartPath");
Stop = game.ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("StopPath");
Destroy = game.ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("DestroyPath");
}
local paths = {}
local function Create(Agent)
if Agent:IsA("Model") and Agent:FindFirstChild("Humanoid") and Agent:FindFirstChild("HumanoidRootPart") and not paths[Agent] then
paths[Agent] = SimplePath.new(Agent)
end
return paths[Agent] --can be ignored for sure
end
local function Start(Agent, Destination) --specific agent to pathfind
local path = paths[Agent]
if path then
print("RUNNING") --it prints but agent doesnt pathfinds?
path:Run(Agent.HumanoidRootPart.Position + Vector3.new(math.random(15, 20), 0, math.random(15, 20)))
end
end
local function Stop(Agent) --specific agent to stop
print("stop called")
if paths[Agent] then
if not SimplePath.StatusType.Idle then
paths[Agent]:Stop()
end
end
end
local function Destroy(Agent) --destroy Path (used when agent is dead)
print("destroy called")
paths[Agent]:Destroy()
paths[Agent] = nil
end
events.Create.OnClientEvent:Connect(Create)
events.Start.OnClientEvent:Connect(Start)
events.Stop.OnClientEvent:Connect(Stop)
events.Destroy.OnClientEvent:Connect(Destroy)
I wonder what makes simple path switching from pathfinding routes so quickly without much delay
I believe it does, but take quite a while