I am making a boss fight and 1 of the attacks is the boss attacking the player multiple times by rising from underneath the ground and when the boss is above ground, he’ll breath toxic gas out which you have to hide from. After the gas disolves, the boss goes back in. The script was perfect but I decided to use runService to make the fight persizer. Inside the runService function I also have task.wait. I need it because I want multiple things to appear, then get destroyed again. The script works really well but some scripters pointed out I shouldnt use task.wait with runService. But how am I supposed to control when certain things in the fight appear and get destroyed?
RunSerive.Heartbeat:Connect(function()
local function enemyChallenge(player)
if player then
for i = 1, 11 do
local character = player.Character
local humanoidRootPart = character.HumanoidRootPart
local rightFoot = character.RightFoot
local raycast = game.Workspace:Raycast(rightFoot.Position, -rightFoot.CFrame.UpVector * 100)
if raycast then
local newTarget = target:Clone()
newTarget.Position = raycast.Position
newTarget.Parent = game.Workspace
local newDirt = dirt:Clone()
newDirt.Position = raycast.Position
newDirt.Parent = game.Workspace
task.wait(0.9)
local newEnemy = enemy:Clone()
newEnemy:SetPrimaryPartCFrame(newDirt.CFrame - Vector3.new(0, 10, 0))
newEnemy.Parent = game.Workspace
task.wait(2)
newEnemy:Destroy()
newTarget:Destroy()
newDirt:Destroy()
end
task.wait(1)
end
end
local fight = false
end
end)
that’s the main part of the script I’m focusing on in this post.
It only tries to run enemyChallenge once at a time avoid potential timing conflicts
The task.wait()'s are executed on a separate thread leaving the Heartbeat callback unblocked
It throttles the enemyChallenge check to only occur at RUN_CHECK_FREQ_SEC time periods thus freeing up CPU, etc. when you probably don’t need to be checking every Heartbeat.
local RunningCheck = false
local RUN_CHECK_FREQ_SEC = 3
local RunCheckCurrent = 0
local function enemyChallenge(player)
if player then
for i = 1, 11 do
local character = player.Character
local humanoidRootPart = character.HumanoidRootPart
local rightFoot = character.RightFoot
local raycast = game.Workspace:Raycast(rightFoot.Position, -rightFoot.CFrame.UpVector * 100)
if raycast then
local newTarget = target:Clone()
newTarget.Position = raycast.Position
newTarget.Parent = game.Workspace
local newDirt = dirt:Clone()
newDirt.Position = raycast.Position
newDirt.Parent = game.Workspace
task.wait(0.9)
local newEnemy = enemy:Clone()
newEnemy:SetPrimaryPartCFrame(newDirt.CFrame - Vector3.new(0, 10, 0))
newEnemy.Parent = game.Workspace
task.wait(2)
newEnemy:Destroy()
newTarget:Destroy()
newDirt:Destroy()
end
task.wait(1)
end
end
RunningCheck = false
local fight = false
end
RunService.Heartbeat:Connect(function(step)
RunCheckCurrent += step
if RunCheckCurrent > RUN_CHECK_FREQ_SEC and not RunningCheck then
RunningCheck = true
RunCheckCurrent = 0
task.spawn(enemyChallenge)
end
end)
I also couldn’t see where the player parameter was coming from that is declared for enemyChallenge… I ignored it. You’ll need to adapt the solution to your context. The structure is sound and avoids the problem of using task.wait within Heartbeat.
In your original post, where is enemyChallenge being called from? Something has to pass the player param or your code won’t execute the way you want.
In my example it would look like this:
RunService.Heartbeat:Connect(function(step)
RunCheckCurrent += step
if RunCheckCurrent > RUN_CHECK_FREQ_SEC and not RunningCheck then
RunningCheck = true
RunCheckCurrent = 0
task.spawn(enemyChallenge, player) -- <=== but where does "player" come from??
end
end)
This is the second time you’ve said this but it doesn’t make sense - players does not equal player. In your original post, the code you’ve shown is passing player to the enemyChallenge function (as show in my screenshot).
Given you are likely not passing player to enemyChallenge I wouldn’t expect it to do anything because if player then will be false given player doesn’t appear to be defined.
this part of the script was copied of a tutorial. All I know is, that it works very well. My bigger question though is why I cant use task.wait inside runService?
I’ll leave you with this: this code is almost certainly wrong
RunSerive.Heartbeat:Connect(function()
local function enemyChallenge(player)
There are very few reasons you would ever declare a function within the Heartbeat.
Second, using task.wait within the Heartbeat will lead to bugs and should not be done. The solution I posted is the best effort I can give at showing a better solution given the information you’ve provided. Because you were not able to copy/paste it to work is not surprising given the incompleteness of said information. The structure of my solution is a correct one to solve these problems, again, given the limited information I have at hand.
I’m so sorry for how dumb I was yesterday. It was just very late and I had tried to solve this problem from the point I woke up until making this post. You’re script IS correct. It’s just me who was weird