I’m making an NPC system, which follows a path set in a table of positions. The script loops through the table, and executes this function with the position. This script moves the NPC towards the position and changes the movedirection attribute which another script uses to rotate the NPC towards the position. (Which is why it uses heartbeat)
A problem I found though is the NPCs stop for like a millisecond after getting to each position which can be noticeable at times and I want it to be smooth. I’m not sure if it’s caused by the task.wait() at the bottom because I tried removing it and putting all the positions in the heartbeat but the issue was still visible. (Not 100% sure though, that’s just what I found with testing)
Function with the problem
local MoveTo = {}
local replicatedStorage = game:GetService("ReplicatedStorage")
local settingsModule = require(replicatedStorage.ModuleScripts.Settings)
local moveAcceleration = settingsModule["WALK_ACCELERATION"]
local RunS = game:GetService("RunService")
function MoveTo.MoveToPosition(humanoid, rootPart, position)
local connection
local moveDirection = humanoid:GetAttribute("MoveDirection")
humanoid:SetAttribute("MoveDirection", (Vector3.new(position.X, 0, position.Z) - Vector3.new(rootPart.Position.X, 0, rootPart.Position.Z)).Unit)
local targetMoveVelocity = Vector3.new()
local moveVelocity = Vector3.new()
local moveVelocityInt = 0
connection = RunS.Heartbeat:Connect(function(dt)
if humanoid and rootPart then
local distance = (Vector3.new(position.X, 0, position.Z) - Vector3.new(rootPart.Position.X, 0, rootPart.Position.Z)).Magnitude
if distance > 3.5 then
if distance > 4 then
humanoid:SetAttribute("MoveDirection", (Vector3.new(position.X, 0, position.Z) - Vector3.new(rootPart.Position.X, 0, rootPart.Position.Z)).Unit)
end
local moveDir = humanoid:GetAttribute("MoveDirection")
if moveDir then
if moveDir == Vector3.zero then
moveVelocityInt = math.clamp(moveVelocityInt - (dt * moveAcceleration / 2), 0,1)
else
moveVelocityInt = math.clamp(moveVelocityInt + (dt * moveAcceleration / 2), 0,1)
end
humanoid:Move(rootPart.CFrame.LookVector.Unit*moveVelocityInt)
end
else
--humanoid:SetAttribute("MoveDirection", Vector3.zero)
if math.random(1,10) >= 10 then
task.wait(math.random(2,4))
else
--humanoid:Move(Vector3.zero)
end
connection:Disconnect()
end
else
connection:Disconnect()
end
end)
repeat task.wait() until not connection.Connected
end
return MoveTo
Server Script which calls the function
local function startMovement(NPC, NPCRoot, NPCHum)
local position = calculateRandomPosition(NPCRoot)
if not position then return end
local path = pathfinder.FindPath(NPCRoot.Position, position)
if path then
for _, pos in ipairs(path) do
moveToModule.MoveToPosition(NPCHum, NPCRoot, pos)
end
startMovement(NPC, NPCRoot, NPCHum)
end
end
pathfinder:Init()
for _, NPC in pairs(workspace.ActiveNPCs:GetChildren()) do
local nodesTable = nodes:GetChildren()
local NPCRoot = NPC:WaitForChild("HumanoidRootPart")
local NPCHum = NPC:WaitForChild("Humanoid")
local randomNumber = math.random(1, #nodesTable)
local node = nodesTable[randomNumber]
local position = node.Value
NPC:SetPrimaryPartCFrame(CFrame.new(position))
task.spawn(function()
startMovement(NPC, NPCRoot, NPCHum)
end)
end
Video of what happens
You can see they stop for like a milisecond before continuing to the next node