Hi, essentially I can’t get a mob to move toward a player (for whatever reason). I’ve tried looking for sources and debugging but nothing has worked. The mob wont move, it just stands there. There are no errors.
Main.script:
local Players = game:GetService("Players")
local mob = require(script.Mob)
local map = workspace.DeadCenter
for wave=1, 5 do
print("wave:", wave)
if wave < 5 then
mob.Spawn("Zombie", 3 * wave, map)
end
repeat
task.wait(1)
until #map.Mob:GetChildren() == 0
print("wave", wave, "ended")
task.wait(1)
end
game.Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function()
mob.moveToPlayer(player, map)
end)
end)--
Mob.modulescript: (inside of Main.script)
local ServerStorage = game:GetService("ServerStorage")
local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local CollectionService = game:GetService("CollectionService")
local mob = {}
-- Spawning
function mob.Spawn(name, quantity, map)
local mobExists = ServerStorage.Mobs:FindFirstChild(name)
if mobExists then
for i=1, quantity do
task.wait(0.5)
local newMob = mobExists:Clone()
newMob.HumanoidRootPart.CFrame = map.Start.CFrame
newMob.Parent = map.Mob
end
else
warn("Requested mob doesn't exist:", name)
end
end
function mob.moveToPlayer(player, map)
local mobs = game.Workspace.Mob:GetChildren()
for _, mob in ipairs(mobs) do
local humanoid = mob:WaitForChild("Humanoid")
local playerCharacter = player.Character
if playerCharacter then
local humanoidRootPart = playerCharacter:FindFirstChild("HumanoidRootPart")
if humanoidRootPart then
local path = PathfindingService:CreatePath({
AgentRadius = 1,
AgentHeight = 3,
AgentCanJump = true,
AgentCanClimb = true,
})
path:ComputeAsync(mob.PrimaryPart.Position, humanoidRootPart.Position)
path:MoveTo(mob.HumanoidRootPart)
end
end
end
end
return mob
Firstly you are literally calling MoveTo on a path which will cause an error. Along with that you are telling it to stay in place by moving to it’s own HumanoidRootPart. Try to do this instead:
for i, waypoint in pairs(path:GetWaypoints()) do --get path to move to player
humanoid:MoveTo(waypoint.Position) -- move mob to each waypoint
end
Secondly CharacterAdded may sometimes not fire due to the script running after the character spawned, add this line before it:
if player.Character then -- if character existed already then move mobs to player
mob.moveToPlayer(player, map)
end
Last but not least these aren’t even the same destination, causing the script to not find any mobs
Grassperson has already answered your question and this is more of a suggestion, however I would recommend you listen for the ChildRemoved event on your mob folder and check if every mob has been removed then instead of every second. That way you can avoid unnecessary script runtime and there won’t be a delay between the last mob being removed and the wave ending.
By the time player.CharacterAdded fires the player parameter given by .PlayerAdded is going to be undefined since the Lua garbage collector removes it. You should instead take the character parameter passed by .CharacterAdded and pass it to game.Players:GetPlayerFromCharacter().
This is actually incorrect, I just noticed the compiler does not actually garbage collect the player parameter.
I’ve followed your steps and the mobs are still standing still. I’ll post the code-
main.script:
local Players = game:GetService("Players")
local mob = require(script.Mob)
local map = workspace.DeadCenter
for wave=1, 5 do
print("wave:", wave)
if wave < 5 then
mob.Spawn("Zombie", 3 * wave, map)
end
repeat
task.wait(1)
until #map.Mob:GetChildren() == 0 --onChildRemoved
print("wave", wave, "ended")
task.wait(1)
end
game.player.PlayerAdded:Connect(function(player)
if player.Character then -- if character existed already then move mobs to player
mob.moveToPlayer(player, map)
end
player.CharacterAdded:Connect(function() -- character connected
mob.moveToPlayer(player, map)
end)
end)
mob.script:
local ServerStorage = game:GetService("ServerStorage")
local PathfindingService = game:GetService("PathfindingService")
local CollectionService = game:GetService("CollectionService")
local Players = game:GetService("Players")
local mob = {}
-- Spawning
function mob.Spawn(name, quantity, map)
local mobExists = ServerStorage.Mobs:FindFirstChild(name)
if mobExists then
for i=1, quantity do
task.wait(0.5)
local newMob = mobExists:Clone()
newMob.HumanoidRootPart.CFrame = map.Start.CFrame
newMob.Parent = map.Mob
end
else
warn("Requested mob doesn't exist:", name)
end
end
function mob.moveToPlayer(player, map)
local mobs = map.Mob:GetChildren()
for _, mob in ipairs(mobs) do
local humanoid = mob:WaitForChild("Humanoid")
local playerCharacter = player.Character
if playerCharacter then
local humanoidRootPart = playerCharacter:FindFirstChild("HumanoidRootPart")
if humanoidRootPart then
local path = PathfindingService:CreatePath({ -- pathfind
AgentRadius = 1,
AgentHeight = 3,
AgentCanJump = true,
AgentCanClimb = true,
})
path:ComputeAsync(mob.PrimaryPart.Position, humanoidRootPart.Position)
--path:MoveTo(mob.HumanoidRootPart)
for i, waypoint in pairs(path:GetWaypoints()) do --get path to move to player
humanoid:MoveTo(waypoint.Position) -- move mob to each waypoint
end
end
end
end
end
return mob
Oh, ok. If that’s the problem, what would be an optimised way of calling the function constantly? I don’t want to constantly do loops to keep calling the function, I presume that would cause performance issues.
I would recommend you only call your function every few frames to lower the amount of computations. You will have to find a balance between performance and update speed. The only way to update a path is to call :ComputeAsync() again.
Yeah you will have to make a function to check if a wave has ended. You should also refactor your code to use recursion. When the wave ended function fires from the event it should fire a function to start the next wave.