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.
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.
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?
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
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
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
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
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
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).