Zombie Pathfinding works like a slideshow

Don’t bother yourself with LOLLLLLLLLL_1’s response, it’s AI generated gibberish.

Anyways, so another thing is that you don’t need to generate a new path every for every single iteration of the loop. Instead, while pathfinding, you need to worry about whether or not the target can be reached from the last waypoint. If not, a new path will need to be generated, otherwise the current one will work.

1 Like

If the last waypoint sees a path to the player, should I move the zombie to the last waypoint or to the actual player?

if isVisible(self.lastWaypoint.Position, self.target.Position) == true then
					
	self.humanoid:MoveTo(self.target.Position) --HERE!!!!!!!!!!!!!!!!!!
					
	print("Visible")
					
else

Side note:
Problem is that what if the zombie sees the player from a window and doesn’t understand that it’s stuck

I’m assuming you’ve made the zombie simply use MoveTo() on the player if they don’t need to path.

If the CanReach function is run onto the last waypoint, that guarentees that moving to the last waypoint will get the NPC to a point where they don’t need to use pathfinding to reach their target.

There’s probably a better way to do this, but you could put a invisible part over empty areas (like a barricaded window without any glass) and use that instead. It should probably be given a unique collision group to allow players to physically move through it while preventing it from giving positive on line of sight checks.

1 Like

Alright thanks for the advice.

My idea from all of this is that I should check if the zombie can see the player, and if it currently can, it will follow the player. If the player gets out of the zombie’s line of sight, the zombie will build a path to that player.

Also btw: When you say last waypoint do you mean the actual last waypoint of the path or the latest waypoint the zombie travelled to?

Is the pathfinding lag only when hes chasing a player or does it occur all the time even behind walls

If it only occurs when its near the player like these guys said just perform a raycast to decide

It’s not lag it just looks laggy. Even if I use the basic move to() it looks like it’s lagging so it might be something to do with a task.wait() or the loop

Well thats old roblox pathfinding for ya

Try using a* if this doesnt sort itself out

Hey if you’re controlling the zombie via the Server make sure you set the NetworkOwner to nil on the HumanoidRootPart

Zombie.HumanoidRootPart:SetNetworkOwner(nil)

If you’re controlling it via the client make sure the Player is the NetworkOwner

Zombie.HumanoidRootPart:SetNetworkOwner(Player)

EDIT: Saw someone already suggested this. (You only need to set the NetworkOwner once, not every frame)

1 Like

I did do that already… I think it’s something to do with task.wait() or the looping of code

When pathfinding, you don’t need to do task.wait() when looping through the Waypoints

This is a basic loop of the waypoints for reference

for _, waypoint in pairs(waypoints) do
 if waypoint.Action == Enum.PathWaypointAction.Jump then
  Humanoid.Jump = true
 end
 Humanoid:MoveTo(waypoint.Position)
 Humanoid.MoveToFinished:Wait()
end

I’m talking about how long each while loop is for the pathfinding using while task.wait(some time) do

sorry if this doesn’t help, but honestly I couldn’t be asked to read through all the replies.

Assuming the zombie is in visual of the player already and does not need to pathfind anymore, just directly MoveTo the player.
MoveTo has a 2nd parameter, it might help to add the rootpart of the player so the position where the zombie needs to walk to updates in real time, not every task.wait(num) loop.

Your issue seems to be Humanoid.MoveToFinished:Wait(), it’s literally doing what it’s meant for, it’s making the code wait for the humanoid to finish a destination, and on top of that if you add a task.wait() along side it, it’s gonna take even longer to start moving.

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")

local npc = script.Parent
local npcRoot = npc.HumanoidRootPart
local npcHumanoid = npc.Humanoid

task.wait(1)

-- this is better than MoveToFinished() because every 0.1s the path is simply replaced with the next one and never yields
while task.wait(0.1) do
	for _, player in Players:GetPlayers() do
		if not player.Character then continue end

		local path = PathfindingService:CreatePath() :: Path
		local humanoid = player.Character:FindFirstChildOfClass("Humanoid")

		if humanoid and humanoid.Health > 0 then
			path:ComputeAsync(npcRoot.Position, humanoid.RootPart.Position)

			local waypoints = path:GetWaypoints()

			if path.Status == Enum.PathStatus.Success then

				for i, waypoint in waypoints do

					npcHumanoid:MoveTo(waypoint.Position)
					--npcHumanoid.MoveToFinished:Wait()

				end

			end

		end
	end
end
1 Like

Here’s an improved version because I realized that MoveToFinished() is very needed for pathfinding (sorry I don’t use pathfinding at all, but glad I keep researching it)

What you have to do is to call MoveToFinished() only if the magnitude between the zombie and the player is higher than a certain threshold, in the case of this video, I used a threshold of > 10.

Here’s the code once again (fun fact: I forgot to even use SetNetworkOwner())

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")

local npc = script.Parent
local npcRoot = npc.HumanoidRootPart
local npcHumanoid = npc.Humanoid

local f = Instance.new("Folder", workspace)

task.wait(1)

while task.wait(0.1) do
	f:ClearAllChildren()
	
	for _, player in Players:GetPlayers() do
		if not player.Character then continue end

		local path = PathfindingService:CreatePath() :: Path
		local humanoid = player.Character:FindFirstChildOfClass("Humanoid")

		if humanoid and humanoid.Health > 0 then
			path:ComputeAsync(npcRoot.Position, humanoid.RootPart.Position)

			local waypoints = path:GetWaypoints()

			if path.Status == Enum.PathStatus.Success then

				for i, waypoint in waypoints do
					
					local part = Instance.new("Part")
					part.CanCollide = false
					part.Anchored = true
					part.Material = "Neon"
					part.BrickColor = BrickColor.new("White")
					part.Position = waypoint.Position
					part.Shape = "Ball"
					part.Size = Vector3.new(1,1,1)
					part.Parent = f
					
					local npcPos = npcRoot.Position
					local plrPos = humanoid.RootPart.Position
					local dist = (npcPos - plrPos).Magnitude
					
					npcHumanoid:MoveTo(waypoint.Position)
					
					if dist > 10 then
						npcHumanoid.MoveToFinished:Wait()
					end

					if dist < 3 then
						humanoid:TakeDamage(3)
					end

				end

			end

		end
	end
end
1 Like

I applied the code to a function.

Does this look right because it still doesn’t want to work without looking really laggy

function zombie:testPathfind()
	
	self:threadSpawn(function()
		
		while task.wait(0.1) do

			for _, player in Players:GetPlayers() do
				if not player.Character then continue end

				local path = PathfindingService:CreatePath() :: Path
				local humanoid = player.Character:FindFirstChildOfClass("Humanoid")

				if humanoid and humanoid.Health > 0 then
					path:ComputeAsync(self.root.Position, humanoid.RootPart.Position)
					
					self.target = humanoid.RootPart

					local waypoints = path:GetWaypoints()

					if path.Status == Enum.PathStatus.Success then

						for i, waypoint in waypoints do

							local part = Instance.new("Part")
							part.CanCollide = false
							part.Anchored = true
							part.Material = "Neon"
							part.BrickColor = BrickColor.new("White")
							part.Position = waypoint.Position
							part.Shape = "Ball"
							part.Size = Vector3.new(1,1,1)
							part.Parent = game.Workspace

							local npcPos = self.root.Position
							local plrPos = humanoid.RootPart.Position
							local dist = (npcPos - plrPos).Magnitude

							self.humanoid:MoveTo(waypoint.Position)

							if dist > 10 then
								self.humanoid.MoveToFinished:Wait()
							end

							self:attack()

						end

					end

				end
			end
		end
		
	end)
	
	
	return self
	
end

At this point I might just restart

It does look right, but if the problem persists, try removing self:threadSpawn() and the Instance.new(“Part”) because the instantiation spam will cause even more lag.

If you want to restart, here’s some things I discovered that you should adhere to in order to make it work perfectly:

As mentioned above by the other users; Humanoid.MoveToFinished:Wait() has to be called only if the zombie doesn’t have a line of sight of the player or the distance between both of them are greater than a certain threshold (> 10), this is to ensure the humanoid moves along the generated path nicely and doesn’t get stuck because of many obstacles while displaying smooth displacement when closer to players.

I tried to make a line of sight using raycast, but I’m too sleepy to even get it work right now. The theory was to raycast from the zombie towards the player and if it hits anything other than the player’s character, it should abide the Humanoid.MoveToFinished:Wait().

Copy and paste the ‘Animate’ code inside a server script whose RunContext is set to ‘Client’ so that it can run in the workspace inside the zombie’s model and play the animations 100% locally (just like in the videos I shared).

1 Like

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