NPC takes a break from moving before moving again

Heya everyone.

I’m rewriting a OOP NPC System. The issue I’m having is that the NPC prematurely stops before moving again. I know this is because of how the Pathfind function works as I’m skipping the first waypoint to prevent the NPC from only moving to original position of its enemies. The issue is that I don’t know a way to not only skip the first waypoint but also constantly move.

--[[SERVICES]]--
local Players = game:GetService("Players")
local PathfindingService = game:GetService("PathfindingService")

--[[NPC MODEL FOLDERS]]--
local NPCFolder = game:GetService("ServerScriptService").NPCS
local NoobsFolder = NPCFolder.Noobs

--[[MODULE]]--
local BaseNPCModule = {}
BaseNPCModule.__index = BaseNPCModule

function BaseNPCModule:CreateNPC(UnitName, UnitTeam, Special)
	--//Checking to see if the unit exists.
	for _, FindUnit in pairs(NoobsFolder:GetChildren()) do
		if FindUnit:IsA("Model") and FindUnit.Name == UnitName then
			
			--//Creating the unit.
			self.Unit = FindUnit:Clone()
			self.Humanoid = self.Unit:FindFirstChildWhichIsA("Humanoid")
			self.Unit.Parent = game.Workspace
			self.UnitTeam = game:GetService("CollectionService"):AddTag(self.Unit, UnitTeam)
			self.Is_Special = Special
			
			
			
			--//Giving it functionality
			task.spawn(function()
				task.wait(1)
				while task.wait() do
					local Target = BaseNPCModule:FindNearestTargets()
					
					if Target then
						BaseNPCModule:Pathfind(Target)
					end
				end
			end)
		end
	end
end

function BaseNPCModule:FindNearestTargets()
	local Target = nil
	
	for _, PossibleTargets in ipairs(workspace:GetChildren()) do
		if PossibleTargets:IsA("Model") and PossibleTargets:FindFirstChildWhichIsA("Humanoid") then
			local Humanoid = PossibleTargets:FindFirstChildWhichIsA("Humanoid")
			if Humanoid.Health <= 1 then
				--//They're dead.
				return
			end
			
			--//If they aren't dead, check the distance.
			local Distance = (PossibleTargets.PrimaryPart.Position - self.Unit.PrimaryPart.Position).Magnitude
			if Distance <= math.huge then
				
				if PossibleTargets:HasTag("Zombies") then
					Target = PossibleTargets
				end
				
			end
		end
	end
	
	return Target
end

function BaseNPCModule:Pathfind(Target)
	local NewPath = PathfindingService:CreatePath()
	NewPath:ComputeAsync(self.Unit.PrimaryPart.Position, Target.PrimaryPart.Position)
	if NewPath.Status == Enum.PathStatus.Success then
		local Waypoints = NewPath:GetWaypoints()
		
		for i, Waypoint in ipairs(Waypoints) do
			if i <= 2 then continue end
			if Waypoints[4] then
				self.Humanoid:MoveTo(Waypoints[4].Position)
				
				local TimeOut = self.Humanoid.MoveToFinished:Wait()
				if not TimeOut then
					warn("NPC got stuck... Recalculating!")
					BaseNPCModule:Pathfind(Target)
				end
			end
		end
	end
end

return BaseNPCModule
3 Likes

I took a glance at the script and I think it might possibly be this? Not sure if it’s just part of the script or if it’s the problem.

image

You have to set the network owner of the primarypart to nil like this:

Npc.PrimaryPart:SetNetworkOwner(nil)

image

Your main issue is that you do a task.wait(1), try changing the task.wait(1) to a task.wait()

Doesn’t work, sadly. I’ve also tried the solution above but it doesn’t work as well

After reviewing your code, it was just a missing task.spawn when calling the Pathfind function making it yield until the NPC finished moving

Here’s your fixed code

--[[SERVICES]]--
local Players = game:GetService("Players")
local PathfindingService = game:GetService("PathfindingService")

--[[NPC MODEL FOLDERS]]--
local NPCFolder = game:GetService("ServerScriptService").NPCS
local NoobsFolder = NPCFolder.Noobs

--[[MODULE]]--
local BaseNPCModule = {}
BaseNPCModule.__index = BaseNPCModule

function BaseNPCModule:CreateNPC(UnitName, UnitTeam, Special)
	--//Checking to see if the unit exists.
	for _, FindUnit in pairs(NoobsFolder:GetChildren()) do
		if FindUnit:IsA("Model") and FindUnit.Name == UnitName then

			--//Creating the unit.
			self.Unit = FindUnit:Clone()
			self.Humanoid = self.Unit:FindFirstChildWhichIsA("Humanoid")
			self.Unit.Parent = game.Workspace
			self.UnitTeam = game:GetService("CollectionService"):AddTag(self.Unit, UnitTeam)
			self.Is_Special = Special



			--//Giving it functionality
			task.spawn(function()
				while task.wait(0.05) do
					task.spawn(function()
						local Target = BaseNPCModule:FindNearestTargets()

						if Target then
							BaseNPCModule:Pathfind(Target)
						end
					end)
				end
			end)
		end
	end
end

function BaseNPCModule:FindNearestTargets()
	local Target = nil

	for _, PossibleTargets in ipairs(workspace:GetChildren()) do
		if PossibleTargets:IsA("Model") and PossibleTargets:FindFirstChildWhichIsA("Humanoid") then
			local Humanoid = PossibleTargets:FindFirstChildWhichIsA("Humanoid")
			if Humanoid.Health <= 1 then
				--//They're dead.
				return
			end

			--//If they aren't dead, check the distance.
			local Distance = (PossibleTargets.PrimaryPart.Position - self.Unit.PrimaryPart.Position).Magnitude
			if Distance <= math.huge then

				if PossibleTargets:HasTag("Zombies") then
					Target = PossibleTargets
				end

			end
		end
	end

	return Target
end

function BaseNPCModule:Pathfind(Target)
	local NewPath = PathfindingService:CreatePath({
		AgentRadius = 3,
		AgentHeight = 5,
		AgentCanJump = true,
	})
	NewPath:ComputeAsync(self.Unit.PrimaryPart.Position, Target.PrimaryPart.Position)
	if NewPath.Status == Enum.PathStatus.Success then
		local Waypoints = NewPath:GetWaypoints()

		for i, Waypoint in ipairs(Waypoints) do
			if i <= 2 then continue end
			if Waypoints[4] then
				self.Humanoid:MoveTo(Waypoints[4].Position)

				local TimeOut = self.Humanoid.MoveToFinished:Wait()
				if not TimeOut then
					warn("NPC got stuck... Recalculating!")
					BaseNPCModule:Pathfind(Target)
				end
			end
		end
	end
end

return BaseNPCModule
1 Like

Works like a charm, thank you so much!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.