Why can't I use task.wait with runService?

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.

3 Likes

Something I think is better below.

It is better because:

  • 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)
1 Like

in this line RunService.Heartbeat:Connect(function(step) runservice ir orange

1 Like

also thats the error: ServerScriptService.bossScript:68: attempt to index nil with ‘Heartbeat’

1 Like

I just spelled RunService correctly because then my autocomplete worked better :slight_smile:

You spelled it RunSerive in your post.

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.

1 Like

ok I changed that and no errors! But also nothing is happening

there actually is a 2nd script which ties in with this 1, would u like to see it?

1 Like

Probably because of this… as mentioned:

I also couldn’t see where the player parameter was coming from that is declared for enemyChallenge … I ignored it.

1 Like

local players = game:GetService("Players") for players

here is the script that ties with it, its in a tool:

local prompt = script.Parent.ProximityPrompt
game.Players.PlayerAdded:Connect(function(player)

	local inFight = Instance.new("BoolValue")
	inFight.Name = "InFight"
	inFight.Parent = player



	local Touch = script.Parent:WaitForChild("TouchInterest")
	Touch:Destroy()

	prompt.Triggered:Connect(function(plr)
		plr.InFight.Value = true
		tool.Parent = plr:WaitForChild("Backpack")
		prompt:Destroy()
	end)
end)

I’m referring to this:

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)
1 Like

this line its beeing called from local players = game:GetService("Players")

1 Like

eventhough there are no errors as I said nothing happends, but Im not sure how I would change that

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.

1 Like

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?

All I know is, that it works very well.

Well then I’m not sure what we’re doing here :slight_smile:

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.

Best of luck.

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

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.