repeat wait() until workspace.WalkPositions:findFirstChild("WalkPos_1") local WalkPositions = workspace.WalkPositions:GetChildren() local human = script.Parent.Humanoid local Torso = script.Parent.Torso local positions = {} local manginute = 25 local i,v spawn(function() while wait() do i = math.random(1,#WalkPositions) v = WalkPositions[i] end end) while (v.Value - Torso.Position).magnitude < manginute and not positions[i] do human:MoveTo(v.Value) human.MoveToFinished:wait() table.insert(positions, i, v.Name) table.remove(positions, i - 1) end
Error:
--[[ 14:01:53.802 - Workspace.NPCs.NPC.Pathfinder:14: attempt to index local 'v' (a nil value) 14:01:53.802 - Stack Begin 14:01:53.802 - Script 'Workspace.NPCs.NPC.Pathfinder', Line 14 14:01:53.803 - Stack End ]]--
When the NPC gets in range of a value to follow, it doesn't respond and returns this error.
Use good, meaningful variable names. v
is a bad name for a target
. mangitude
is misspelled -- it's harder to type the correct misspelling than it is to just type the word. positions
is a bad name for something which just tells you if you can walk somewhere, e.g., dontWalk
.
spawn
doesn't start immediately, so i
and v
won't be set immediately -- thus they're nil
the first time around in the loop. A simple solution is to make the second loop the one you spawn
. It would be better to eliminate the spawn
altogether, and use only one loop.
In particular, you're just using it to generate a random target. There's no reason to do that in the background -- just grab it when you check things about target
:
Your second loop doesn't ever stop and doesn't ever break, so it will crash the game. You probably want
while wait() do local target = WalkPositions[math.random(#WalkPositions)] if (target.Value - torso.Position).magnitude < magnitude and not dontWalk[i] then .. do stuff .. end end
I'm not sure what you're trying to accomplish with table.insert
and table.remove
from positions
. Since it starts empty, table.remove(positions, i - 1)
is likely to act strange...
Is your goal to not revisit the same spot twice in a short period? You could just do a simple debounce with spawn, then. Also, there's no reason to expose i
at all. You can just use a dictionary using v
:
repeat wait() until workspace.WalkPositions:FindFirstChild("WalkPos_1") local WalkPositions = workspace.WalkPositions:GetChildren() local human = script.Parent.Humanoid local Torso = script.Parent.Torso local dontWalk = {} local magnitude = 25 while wait() do local target = WalkPositions[math.random(#WalkPositions)] if (target.Value - torso.Position).magnitude < magnitude and not dontWalk[v] then human:MoveTo(target.Value) human.MoveToFinished:wait() dontWalk[target] = true -- Allow the humanoid to revisit this spot in 2 seconds: delay(2, function() dontWalk[target] = false end) end end
Being destructive to the WalkPositions
list, you could even eliminate the dontWalk
dictionary:
while wait() do local target = table.remove( WalkPositions, math.random(#WalkPositions) ) if (target.Value - torso.Position).magnitude < magnitude then -- (do the same stuff) delay(2, function() table.insert(WalkPositions, target) end) else table.insert(WalkPositions, target) -- put it back, since we didn't use it end end
alternatively, for slightly simpler code, you could always take the things out for 2 seconds, even if they weren't used. Unfortunately, this has the possibility of emptying the list, which would cause errors, so a new check has to be put in place:
while wait() do if #WalkPositions >= 1 then -- Only proceed if the list isn't empty local target = table.remove(WalkPositions, math.random(#WalkPositions)) if (target.Value - torso.Position).magnitude < magnitude then -- do the same stuff, except for the delay end delay(2, function() table.insert(WalkPositions, target) end) end end