It’s pretty much self explanatory. I am making a Piggy like game and I tried removing SetNetworkOwner and adding it onto the client, pathfinding NPCs will not try to use the pathfinding at all.
Use SetNetworkOwner?? Or change to the new pathfinding algorithm
I literally stated I tried both, adding and removing the function, does the same thing. And also with both, old and new pathfinding algorithms.
:SetNetworkOwner
only works on the server. You don’t need to manually update the network owner to the nearest player, the engine already does that for you, or you could explicitly call :SetNetworkOwnershipAuto
to let the server decide.
From what I can tell, the AIs are using :MoveTo
, but are not waiting for the MoveToFinished
signal/event of the humanoid to occur. The AI would keep trying to move to the destination, but would ultimately have a seizure lmao.
They indeed use MoveToFinished, but spams it.
:SetNetworkOwner IS set on the server. What I am thinking is how do I make the bots calculate good enough to not slow themselves down (Yes, I am using Heartbeat).
Are you using pathfinding? If so, more NPCs = more pathfinding calls,. which can create yields in pathfinding calculations.
Oh boy… I tri ed to make task.wait(5) on Heartbeat but got avoided.
Here’s a part of a script.
local function fetchPossibleTargets(preferredBP)
local targetCharacters = workspace:GetChildren()
local closestTarget = nil
local closestDistance = targetDistance
local closestHumanoid = nil
local closestRootPart = nil
local potentialTargets = {}
local seeTargets = {}
for _, playerTarget in ipairs(targetCharacters) do
if playerTarget:IsA("Model") and playerTarget ~= script.Parent then
local targetHumanoid = playerTarget:FindFirstChildOfClass("Humanoid")
local targetRootPart = playerTarget:FindFirstChild("HumanoidRootPart")
if targetHumanoid and targetRootPart and targetHumanoid.Health > 0 then
local targetParent = targetRootPart.Parent
if not targetParent:FindFirstChild("Enemy")
and not targetParent:FindFirstChild("Helper")
and not targetParent:FindFirstChild("IsStunned")
and not targetParent:FindFirstChild("SoldierNPC")
and enemyRootPart.Anchored == false then
if targetRootPart then
local distance = (targetRootPart.Position - preferredBP).Magnitude
if distance < closestDistance then
closestDistance = distance
closestTarget = playerTarget
closestHumanoid = targetHumanoid
closestRootPart = targetRootPart
table.insert(potentialTargets, targetRootPart)
local NETWORK_OWNER = Players:GetPlayerFromCharacter(closestTarget)
if NETWORK_OWNER then
enemyRootPart:SetNetworkOwner(NETWORK_OWNER)
end
if #potentialTargets > 0 then
for i, v in ipairs(potentialTargets) do
if checkTarget(v) then
table.insert(seeTargets, v)
end
end
end
end
end
end
end
end
end
return closestRootPart, closestTarget
end
RunService.Heartbeat:Connect(function()
if isChasing == true and enemyRootPart.Anchored == false then
local MainTorso = fetchPossibleTargets(enemyRootPart.Position)
if MainTorso ~= nil then
currentlyWandering = 1
local path = PathfindingService:CreatePath({
AgentCanJump = true,
Costs = {
Water = 20
},
PathSettings = {
SupportPartialPath = true
}
})
destinedPath = PathfindingService:FindPathAsync(enemyRootPart.Position, MainTorso.Position)
coordinatedWaypoints = destinedPath:GetWaypoints()
discontinuedPoints = coordinatedWaypoints
local function checkCurrentPath(t)
local movementI = 3
if movementI > #t then
movementI = 3
end
if t[movementI] == nil and movementI < #t then
repeat
movementI = movementI + 1
task.wait()
until t[movementI] ~= nil
return Vector3.new(1, 0, 0) + t[movementI]
else
movementI = 3
return t[movementI]
end
end
if destinedPath and coordinatedWaypoints or checkCurrentPath(coordinatedWaypoints) then
if checkCurrentPath(coordinatedWaypoints) ~= nil and checkCurrentPath(coordinatedWaypoints).Action == Enum.PathWaypointAction.Walk then
enemyHumanoid:MoveTo(checkCurrentPath(coordinatedWaypoints).Position)
end
if checkCurrentPath(coordinatedWaypoints) ~= nil and checkCurrentPath(coordinatedWaypoints).Action == Enum.PathWaypointAction.Jump then
if isJumping == false then
isJumping = true
enemyHumanoid.Jump = true
task.wait(1.6)
isJumping = false
end
if checkCurrentPath(coordinatedWaypoints) then
enemyHumanoid:MoveTo(checkCurrentPath(coordinatedWaypoints).Position)
end
end
else
for i = 3, #discontinuedPoints do
enemyHumanoid:MoveTo(discontinuedPoints[i].Position)
end
end
elseif MainTorso == nil then
currentlyWandering = 0
destinedPath = nil
coordinatedWaypoints = nil
enemyHumanoid.MoveToFinished:Wait()
end
end
end)
I do know enemyHumanoid.MoveToFinished here is pretty much useless as it doesn’t execute at all.
Heartbeat
is asynchronous, meaning it’ll call again even if the last call was yielded.
This code will continue to run every heartbeat:
local RunService = game:GetService("RunService")
RunService.Heartbeat:Connect(function()
print("foo")
task.wait(5)
print("bar")
end)
Instead, you can create some sort of debounce system. Here are two possible solutions:
local COOLDOWN = 5
local RunService = game:GetService("RunService")
local LastTick = os.clock()
RunService.Heartbeat:Connect(function()
if os.clock() - LastTick < COOLDOWN then
return -- If it hasn't been 5 seconds, don't run
end
LastTick = os.clock()
print("foo")
end)
Or alternatively,
local COOLDOWN = 5
local RunService = game:GetService("RunService")
local Debounce = false
RunService.Heartbeat:Connect(function()
if Debounce then
return
end
Debounce = true
print("foo")
task.wait(COOLDOWN)
print("bar")
Debounce = false
end)
I’ll try both ways, if it works, I’ll mark this as a solution. I’ll play around until I get it working fine.
for odd reason, if it’s off, it will not walk until it’s on, making a lot of pauses along the way.
doing this completely broke it. It just spams isClosed and isOpened all the time, regardless of its debounce.
RunService.Heartbeat:Connect(function()
if isChasing == true and enemyRootPart.Anchored == false then
local MainTorso = fetchPossibleTargets(enemyRootPart.Position)
if MainTorso ~= nil then
if heartbeatCooldown == false then
heartbeatCooldown = false
print("isOpened")
currentlyWandering = 1
local path = PathfindingService:CreatePath({
AgentCanJump = true,
Costs = {
Water = 20
},
PathSettings = {
SupportPartialPath = true
}
})
destinedPath = PathfindingService:FindPathAsync(enemyRootPart.Position, MainTorso.Position)
coordinatedWaypoints = destinedPath:GetWaypoints()
discontinuedPoints = coordinatedWaypoints
local function checkCurrentPath(t)
local movementI = 3
if movementI > #t then
movementI = 3
end
if t[movementI] == nil and movementI < #t then
repeat
movementI = movementI + 1
task.wait()
until t[movementI] ~= nil
return Vector3.new(1, 0, 0) + t[movementI]
else
movementI = 3
return t[movementI]
end
end
if destinedPath and coordinatedWaypoints or checkCurrentPath(coordinatedWaypoints) then
if checkCurrentPath(coordinatedWaypoints) ~= nil and checkCurrentPath(coordinatedWaypoints).Action == Enum.PathWaypointAction.Walk then
enemyHumanoid:MoveTo(checkCurrentPath(coordinatedWaypoints).Position)
end
if checkCurrentPath(coordinatedWaypoints) ~= nil and checkCurrentPath(coordinatedWaypoints).Action == Enum.PathWaypointAction.Jump then
if isJumping == false then
isJumping = true
enemyHumanoid.Jump = true
task.wait(1.6)
isJumping = false
end
if checkCurrentPath(coordinatedWaypoints) then
enemyHumanoid:MoveTo(checkCurrentPath(coordinatedWaypoints).Position)
end
end
else
for i = 3, #discontinuedPoints do
enemyHumanoid:MoveTo(discontinuedPoints[i].Position)
end
end
task.wait(5)
heartbeatCooldown = true
print("isClosed")
heartbeatCooldown = false
end
elseif MainTorso == nil then
currentlyWandering = 0
destinedPath = nil
coordinatedWaypoints = nil
end
end
end)
even if it’s not breaking, it will still keep calculating, making a lot of lags if other npcs are inside the workspace too, so I don’t see the point of doing this.
I did it chat. Instead of RunService.Heartbeat:Connect(function(), I did while RunService.Heartbeat:Wait() do, and now this works much better with 10+ NPCs. Thanks to everyone who read/replied.
You need to check the debounce as the very first part, and rigth after the check, turn on the debounce. Your implementation is incorrect.
that’s exactly what I did… even then, what’s the point doing it? Eventually more and more NPCs will spawn and also manipulate with their own debounce.
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.