The problem is, I don’t know how to delay/wait within a coroutine.
My NPC is supposed to wander around if it can’t find something to attack, but it ends up wiggling around like this:
Is there a way to use wait() within coroutines, or is there a better way I could do this?
Here’s my code.
AI:
local humanoid = script.Parent.Humanoid
local killer = script.Parent
local distance, closestHumanoid
local module = require(game.ServerScriptService:WaitForChild("NearstPlayerModule"))
local maxDistance = 100
local root = killer.HumanoidRootPart
local target
local dmg = 25
local wander = function()
humanoid.WalkSpeed = 16
humanoid:MoveTo(Vector3.new(math.random(-500,500),5.992,math.random(-500,500)))
local ray = workspace:Raycast(killer.HumanoidRootPart.Position,killer.HumanoidRootPart.CFrame.LookVector)
if ray and ray.Instance ~= nil then
humanoid.Jump = true
end
end
local chase = function()
humanoid:MoveTo(closestHumanoid.HumanoidRootPart.Position)
humanoid.WalkSpeed = 40
local ray = workspace:Raycast(killer.HumanoidRootPart.Position,killer.HumanoidRootPart.CFrame.LookVector)
if ray and ray.Instance ~= nil then
humanoid.Jump = true
end
end
local attack = function()
if target then
target:TakeDamage(dmg)
wait(0.5,1.5)
end
end
while true do
distance, closestHumanoid = module.GetClosestPlayer(maxDistance,root,killer)
print(distance,closestHumanoid)
if closestHumanoid and distance <= maxDistance and distance > 15 and closestHumanoid.Humanoid.Health ~= 0 then
local chaseRoutine = coroutine.create(chase)
coroutine.resume(chaseRoutine)
elseif closestHumanoid and distance <= 15 and closestHumanoid.Humanoid.Health ~= 0 then
print("damage!!")
target = closestHumanoid.Humanoid
local attackRoutine = coroutine.create(attack)
coroutine.resume(attackRoutine)
elseif closestHumanoid == nil and distance == nil or closestHumanoid.Humanoid.Health == 0 then
local wanderRoutine = coroutine.create(wander)
coroutine.resume(wanderRoutine)
end
wait()
end
Hi, since coroutines only affect their own thread, using wait will not affect other functions like your while true do loop. The easiest way to get around this is to create a table with values telling the script whether the action is ready. It will take me some minutes to code this
It really depends on the situation. If it’s client based and it’s an action that should wait for the client to continue, you can use wait(). However, if it’s something that HAS to be done in time, you can then use task.wait().
local humanoid = script.Parent.Humanoid
local killer = script.Parent
local distance, closestHumanoid
local module = require(game.ServerScriptService:WaitForChild("NearstPlayerModule"))
local maxDistance = 100
local root = killer.HumanoidRootPart
local target
local dmg = 25
local functionReady = {}
local wander = function()
local function NotReady(value)
functionReady[2] = value
end
NotReady(true)
humanoid.WalkSpeed = 16
humanoid:MoveTo(Vector3.new(math.random(-500,500),5.992,math.random(-500,500)))
NotReady()
local ray = workspace:Raycast(killer.HumanoidRootPart.Position,killer.HumanoidRootPart.CFrame.LookVector)
if ray and ray.Instance ~= nil then
humanoid.Jump = true
end
end
local chase = function()
humanoid:MoveTo(closestHumanoid.HumanoidRootPart.Position)
humanoid.WalkSpeed = 40
local ray = workspace:Raycast(killer.HumanoidRootPart.Position,killer.HumanoidRootPart.CFrame.LookVector)
if ray and ray.Instance ~= nil then
humanoid.Jump = true
end
end
while true do
distance, closestHumanoid = module.GetClosestPlayer(maxDistance,root,killer)
print(distance,closestHumanoid)
if closestHumanoid and distance <= maxDistance and distance > 15 and closestHumanoid.Humanoid.Health ~= 0 then
coroutine.wrap(chase) -- coroutine.wrap really isn't necessary unless a wait is inserted into the function
elseif closestHumanoid and distance <= 15 and closestHumanoid.Humanoid.Health ~= 0 then
local tick = tick()
if not functionReady[1] or tick > functionReady[1] then
target = closestHumanoid.Humanoid
if target then
print("damage!!")
target:TakeDamage(dmg)
functionReady[1] = math.random(0.5,1.5) + tick
end
end
elseif closestHumanoid == nil and distance == nil or closestHumanoid.Humanoid.Health == 0 then
if not functionReady[2] then
coroutine.wrap(wander)
end
end
Now while you can argue that task.wait() is better than wait() due to it being more accurate (wait() has an internal physics-based throttler and updates 2x slower than task.wait()). That doesn’t dismiss wait() as being entirely useless (for now atleast).
Like for example how it has a physics-based throttler (as I mentioned above). This makes it yield more than the expected yield time whenever the server lags due to physics calculations.