Need help NPC Script

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!

  2. I need help making this look it works once but when a new npc spawns it does not work like it stop at the points for a little bit Here’s the script https://youtu.be/qXXIJy_OWcs

  3. What solutions have you tried so far? I tried different way but nothing works I have not looked for solutions on the Creator Hub?

After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!

lua

``` local plot = script.Parent
local npcSpawn = plot.Steps:WaitForChild("NPCSpawn")
local shopPoint = plot.Steps:WaitForChild("ShopPoint")
local stopPoint = plot.Steps:WaitForChild("StopPoint")
local WalkPoint1 = plot.Steps:WaitForChild("WalkPoint1")
local WalkPoint2 = plot.Steps:WaitForChild("WalkPoint2")
local WalkPoint3 = plot.Steps:WaitForChild("WalkPoint3")
local WalkPoint4 = plot.Steps:WaitForChild("WalkPoint4")
local WalkPoint5 = plot.Steps:WaitForChild("WalkPoint5")
local WalkPoint6 = plot.Steps:WaitForChild("WalkPoint6")
local WalkPoint7 = plot.Steps:WaitForChild("WalkPoint7")
local WalkPoint8 = plot.Steps:WaitForChild("WalkPoint8")
local cashPad = plot:WaitForChild("CashPad")
local npcFolderRoot = game.ReplicatedStorage:WaitForChild("CustomerNPCs")
local moneyPopupTemplate = game.ReplicatedStorage:WaitForChild("MoneyPopup")

local isSpawning = false

Ensure CashPad attribute exists
if cashPad:GetAttribute("MoneyStored") == nil then
	cashPad:SetAttribute("MoneyStored", 0)
end

 ===== NPC Configuration =====
local npcConfig = {
	NormalNPCs   = {chance = 0.7, min = 10, max = 25},     
	VIPNPCs      = {chance = 0.25, min = 100, max = 250},  
	SuperVIPNPCs = {chance = 0.01, min = 500, max = 750}  
}

 ===== NPC Pools =====
local npcPool = {}      
local preloadedNPCs = {} 

for folderName, cfg in pairs(npcConfig) do
	npcPool[folderName] = {}
	local folder = npcFolderRoot:FindFirstChild(folderName)
	if folder then
		preloadedNPCs[folderName] = {}
		for _, npcModel in pairs(folder:GetChildren()) do
			table.insert(preloadedNPCs[folderName], npcModel)
			for i = 1, 2 do
				local clone = npcModel:Clone()
				clone.Parent = nil
				table.insert(npcPool[folderName], clone)
			end
		end
	end
end

 ===== Choose a customer =====
local function chooseCustomer()
	local totalWeight = 0
	for _, cfg in pairs(npcConfig) do
		totalWeight += cfg.chance
	end

	local roll = math.random() * totalWeight
	local cumulative = 0
	local chosenFolder

	for folderName, cfg in pairs(npcConfig) do
		cumulative += cfg.chance
		if roll <= cumulative then
			chosenFolder = folderName
			break
		end
	end

	if not chosenFolder or not preloadedNPCs[chosenFolder] then
		return nil, 0, nil
	end

	local npcModels = preloadedNPCs[chosenFolder]
	if #npcModels == 0 then
		return nil, 0, nil
	end

	local npcModel = npcModels[math.random(1, #npcModels)]
	local cfg = npcConfig[chosenFolder]
	local earned = math.random(cfg.min, cfg.max)

	return npcModel, earned, chosenFolder
end

 ===== Get NPC from pool =====
local function getNPC(model, folderName)
	local npc
	if #npcPool[folderName] > 0 then
		npc = table.remove(npcPool[folderName])
		npc.Parent = plot.CustomerFolder
	else
		npc = model:Clone()
		npc.Parent = plot.CustomerFolder
	end

	npc:SetPrimaryPartCFrame(CFrame.new(npcSpawn.Position) * CFrame.Angles(0, math.rad(180), 0))

	local humanoid = npc:FindFirstChildOfClass("Humanoid")
	if humanoid then
		humanoid.Health = humanoid.MaxHealth
		humanoid.WalkSpeed = 9
	end

	return npc
end

 ===== Recycle NPC =====
local function recycleNPC(npc, folderName)
	npc.Parent = nil
	table.insert(npcPool[folderName], npc)
end

===== Spawn a single customer =====
local function spawnCustomer()
	
	if not plot:GetAttribute("Occipied") then return end
	if isSpawning then return end
	isSpawning = true

	local npcModel, earned, folderName = chooseCustomer()
	if not npcModel then
		isSpawning = false
		return
	end

	local npc = getNPC(npcModel, folderName)
	local humanoid = npc:FindFirstChildOfClass("Humanoid")
	
	local animator = humanoid:FindFirstChildOfClass("Animator")
	
	local walkAnim = Instance.new("Animation")
	walkAnim.AnimationId = "rbxassetid://100621370842384"

	local walkTrack
	if animator then
		walkTrack = animator:LoadAnimation(walkAnim)
	end

	local function playWalk()
		if walkTrack and not walkTrack.IsPlaying then
			walkTrack:Play()
		end
	end

	local function stopWalk()
		if walkTrack and walkTrack.IsPlaying then
			walkTrack:Stop()
		end
	end
	
	================================
	idle animation
	===============================

	local IdleAnim = Instance.new("Animation")
	IdleAnim.AnimationId = "rbxassetid://120677824080558"

	local idleTrack
	if animator then
		idleTrack = animator:LoadAnimation(IdleAnim)
	end

	local function PlayIdle()
		if idleTrack and not idleTrack.IsPlaying then
			idleTrack:Play()
		end
	end

	local function StopIdle()
		if idleTrack and idleTrack.IsPlaying then
			idleTrack:Stop()
		end
	end


	if humanoid then
		 Walk to shop
		
		wait(9)
		
		playWalk()
		humanoid:MoveTo(WalkPoint1.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint2.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint3.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint4.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint5.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint6.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint7.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint8.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint8.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint8.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint8.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint8.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint8.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(shopPoint.Position)
		humanoid.MoveToFinished:Wait()
		stopWalk()
		PlayIdle()

		 PAY AT SHOP
		cashPad:SetAttribute("MoneyStored", cashPad:GetAttribute("MoneyStored") + earned)
		print(`"Earned From:", [{npc}] amount [{earned}]`)

		-- Floating money popup
		local popup = moneyPopupTemplate:Clone()
		popup.Adornee = npc.PrimaryPart
		popup.TextLabel.Text = "+" .. earned
		popup.Parent = workspace

		spawn(function()
			local duration = 2
			local startPos = popup.StudsOffset
			local endPos = startPos + Vector3.new(0, 2, 0)
			local steps = 20
			local textLabel = popup.TextLabel

			for i = 1, steps do
				local alpha = i / steps
				popup.StudsOffset = startPos:Lerp(endPos, alpha)
				textLabel.TextTransparency = alpha
				task.wait(duration / steps)
			end

			wait(7)
			popup:Destroy()
		end)

		-- Wait at shop (simulate shopping)
		task.wait(7)
		
		StopIdle()
		playWalk()
		humanoid:MoveTo(WalkPoint8.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint7.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint6.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint5.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint4.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint3.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint2.Position)
		humanoid.MoveToFinished:Wait()
		
		humanoid:MoveTo(WalkPoint1.Position)
		humanoid.MoveToFinished:Wait()
		
		-- Walk to exit
		humanoid:MoveTo(stopPoint.Position)
		humanoid.MoveToFinished:Wait()
		stopWalk()

		-- Recycle NPC
		recycleNPC(npc, folderName)
	end

	task.wait(math.random(2, 6))
	isSpawning = false
end

-- ===== Main loop =====
task.spawn(function()
	task.wait(math.random(13, 25))
	while true do
		if plot:GetAttribute("Occipied") then
			spawnCustomer()
		end
		task.wait(math.random(2, 6))
	end
end) ```

I just want help on the point to point to fix it

do you Need to reset the npcPool table ?
table = nil
table = {}

Actually I see that you recycle the NPC

I am reading that you should add a timeout to : humanoid.MoveToFinished:Wait()
like so:
humanoid.MoveToFinished:Wait(3)

it didn’t work it still stops at the points for a little while and keeps going

1 Like

I’m wondering why you did WalkPoint8, six times back to back ?

humanoid:MoveTo(WalkPoint8.Position)

So I read humanoid.MoveToFinished:Wait() might be timing out.

**Timeout:** MoveTo()has an inherent timeout of approximately 8 seconds. If the NPC doesn't reach the target within that time, theWait()will returnfalse, the thread continues, but the NPC might still be moving or stops abruptly, causing timing issues.

When I watched your video I could not even tell what was going wrong. I did not see the new npc that spawns, stopping at points as explained.

An idea to resolve:
Instead of using MoveToFinished:Wait(), which pauses the script until the destination is reached, use a loop that constantly checks the distance (magnitude) to the current waypoint. Once the NPC is within a certain threshold (e.g., 5 studs), move it to the next waypoint immediately.