Loop stops right after wait or task.wait inside task.spawn(function()

Hello everyone! So i’ve been trying to make turret with module script, and it should work fine, but for some reason when i try using wait or task wait the loop just ends inside task.spawn.

Here’s the script fragment:

PLEASE READ ENTIRE POST WITH NOTES BELOW THE CODE!!!

turret_module.Idle = function(turret_model)
	print("runned")
	turret_module.cancel_task()
	wait(0.5)
	current_task = task.spawn(function()
		print("Started task")
		task.spawn(function()
			print("Starting loop task")
			while true do
				print("loop")
				wait(0.1)
				print("loop2")
				local targets = turret_module.get_avaiable_targets(turret_model)
				print(targets)
				if #targets > 0 then
					turret_module.Spotted(turret_model)
				end
			end
		end)
		print("Starting idle animation")
		while true do
			print("anim")
			wait()
			print("anim2")
			local tween1 = TweenService:Create(turret_model.Main, TweenInfo.new(5, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut), {Orientation = turret_model:GetAttribute("main_rot") + Vector3.new(0, -20, 0)})
			tween1:Play()
			wait(8)
			local tween2 = TweenService:Create(turret_model.Main, TweenInfo.new(5, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut), {Orientation = turret_model:GetAttribute("main_rot") + Vector3.new(0, 20, 0)})
			tween1:Play()
			wait(8)
		end
	end)
end

so when the function rans it just prints out:

  • started task
  • starting loop task
  • loop
  • starting idle animation
  • anim

as you can see it doesnt type loop2 or anim2 which are AFTER the wait, so it means that code doesn’t run for some reason. When i were debugging i added wait(0.5) before the task spawn and what i got is that the code were running like couple times before the 0.5 wait passed even tho there is no way it could repeat. But anyway, i were thinking "oh then cuz of the repeative thingy the task cancels or something so it rans and instantly cancels, so i deleted the cancel_task line of code, but it still happened! I don’t see anything canceling the task so it shouldnt do so. Here is the code running that function:

turret_module.Create = function(pos: Vector3, rotation: Vector3, fov: number, distance: number)
        print("runned create function")
	if not fov then fov = 60 end
	if not distance then distance = 100 end
	if not rotation then rotation = Vector3.new(0,0,0) end
	local turret_model = ServerStorage.Turret:Clone()
	turret_model:SetAttribute("FOV", fov)
	turret_model:SetAttribute("distance", distance)
	turret_model:SetAttribute("main_rot", rotation)
	turret_model:PivotTo(CFrame.new(pos) * CFrame.Angles(rotation.X, rotation.Y, rotation.Z))
	turret_model.Parent = workspace.Turrets 
	
	turret_module.Idle(turret_model)
end

this function shouldnt run few times too, only once, but the print happens couple times in same interval before the 0.5 wait time passes in idle function. Im confused whats going on, i even can give you the code running that creatre function.

script.Parent.Touched:Connect(function(hit)
	local found = false
	if hit.Parent:FindFirstChild("Humanoid") and found == false then
		found = true
		require(game.ServerScriptService.Modules.Turret).Create(Vector3.new(0,3,0), Vector3.new(0,0,0), 60, 100)
		script:Destroy()
	end
end)

as you can see i tried doing everything so it doesnt run a couple times. please help, im very confused!

You might be misunderstanding how Lua threads work internally. When you call spawn, you’re creating another thread that will run immediately and won’t stop until it yields or completes. When a thread yields or completes, the task scheduler will immediately choose to run another thread that is waiting and ready (how exactly it chooses, I’m not sure).

You spawn two threads via current_task = task.spawn(function() ... end) and task.spawn(function() ... end) right after. The second thread will print “loop” and yield because you called wait(0.1). From there, the task scheduler is going find another thread to run while that one waits, and in this case it’ll resume the first thread you created that has been waiting. That’s why you’re seeing “starting idle animation” print right after “loop”.

So it looks seems like you’re calling wait(0.5) which is preventing the script from destroying itself and disconnecting the Touched connections. So in that window that the thread is waiting, Roblox might detect more touched events and run your event handler. Also, you’re immediately setting found to false which means the inner block is going to run every time assuming the instance’s parent has a humanoid instance. I don’t think it’s doing what you’re intending it to do.

All this being said, I think you need to rework your idle function because spawning tasks like that when you’re expecting somewhat sequential behavior is leading to very confusing and hard-to-debug issues.

1 Like

Hm, i think you’re right. I were tired back then so i didn’t think about that. Here’s what i got and it works as expected, runs only once.

local found = false
script.Parent.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid") and found == false then
		found = true
		require(game.ServerScriptService.Modules.Turret).Create(Vector3.new(0,3,0), Vector3.new(0,0,0), 60, 100)
		script:Destroy()
	end
end)

Well, that’s expected, i expected the second task spawn to run along with while true do in first one, by that i mean at the same time. But the problem is that it doesn’t seem to work after wait happens. Everything before wait works, but when wait happens (in both task spawns) they just stop right there and not do anything. Maybe i misunderstood you and how task spawns work again. If so, sorry.

Is there any way to fix that? What i want to achieve is that the search loop inside second task spawn should continiously search for targets while having the animation loop at the same time after that second task spawn inside first task spawn, and when it finds one (target) it starts another module function which runs the same cancel task function which would cancel current_task if it’s not nil. In case you need it, there it is:

turret_module.cancel_task = function()
	print("cancelled task")
	if typeof(current_task) == "thread" then
		task.cancel(current_task)
		current_task = nil
	end
end

I added wait after cancelling task in idle function to prevent the idle function from cancelling itself, somehow. Even tho it shouldn’t really happen. But sadly the wait stopping task spawns entirely problem still remains.

so umm… I tried putting task wait after task spawn and as long as this task wait didn’t pass the task spawn works! But once the task wait passes the task spawn stops working again… Weird. I won’t mark it as solution just yet beacuse i really want to know reason to that. Maybe it somehow linked to module functions?

So you’re saying that “loop 2” never prints?

it didn’t print before but when i put task wait after the task spawn it prints, but as long as task wait didn’t pass just yet.

for example, if i put task.wait(0.5) then in next 0.5 seconds the task spawn will remain working but after 0.5 seconds ends it stops working. For now i just put task.wait(999) so in 999 seconds task spawn will work, but i wonder if there is easier way or at least explanation to that.

I know i can use bigger numbers i just used it for now.

Note: by saying AFTER task spawn i mean after it ends with “end)”, not inside it.