Coroutine vs While True loop or other ideas for a script that runs on proximity

Hi guys, I was wondering if I could get some feedback on how to implement a script that runs when a player enters a certain range of an object. So far I’ve tried to do two methods, using a coroutine and a while true loop. The goal of this script is just to have some pictures cycle on a few surface GUIs when a player gets within some range of another block.

Note for both scripts, “parent” refers to a sphere that is in a different collision group as the player that will not collide with them. This will trigger touched event.

Coroutine implementation: This method does not work properly at the moment, since the coroutine is always in a suspended state, my checking of conditions on event firing does not work.

local function cyclePictures()
	
	while true do
		pic2.ImageTransparency = 0
		tween1:Play()
		wait(15)
		pic3.ImageTransparency = 0
		tween2:Play()
		wait(15)
		tween3:Play()
		wait(15)
		pic1.ImageTransparency = 0
		
		local stillTouching = false

		for index,value in ipairs(parent:GetTouchingParts()) do
			if value.Parent:FindFirstChild("Humanoid") and value.Name == "HumanoidRootPart" then
				stillTouching = true
				break
			end
		end

		if stillTouching == false then
			coroutine.yield()
		end
	end
	
end

local cycleCoro = coroutine.create(cyclePictures)

local function startCycle(hit)
	
	if hit.Name == "HumanoidRootPart" and hit.Parent:FindFirstChild("Humanoid") then
		if coroutine.status(cycleCoro) == "suspended" then
			coroutine.resume(cycleCoro)
		end
	end
	
end

parent.Touched:Connect(startCycle)

While True implementation: I’m not sure the overall performance impact this will have if say 100 or 200 of these are always running.

local function cyclePics()
	while true do
		pic2.ImageTransparency = 0
		tween1:Play()
		wait(15)
		pic3.ImageTransparency = 0
		tween2:Play()
		wait(15)
		tween3:Play()
		wait(15)
		pic1.ImageTransparency = 0

		local stillTouching = false
		local connection = parent.Touched:Connect(function() end)
		while stillTouching == false do
			for index,value in ipairs(parent:GetTouchingParts()) do
				print(value.Name)
				if value.Name == "HumanoidRootPart" then
					stillTouching = true
					print("it worked")
					break
				end
			end
			wait(5)
		end
		connection:Disconnect()
	end
end

cyclePics()
1 Like

I recommend using ZonePlus from ForeverHD Instead of making it, It have many features. Also, It is really light-weight.

API Documentation is here: Zone - ZonePlus

1 Like

Wow, thanks a ton! This saves me a lot of work! :grinning:

Here is the final implementation for anyone curious:

local function cyclePics()
	while true do
		pic2.ImageTransparency = 0
		tween1:Play()
		wait(15)
		pic3.ImageTransparency = 0
		tween2:Play()
		wait(15)
		tween3:Play()
		wait(15)
		pic1.ImageTransparency = 0

		local playersArray = spherezone:getPlayers()
		
		if #playersArray == 0 then
			parent:SetAttribute("iscycling",false)
			break
		end
	end
end

local function startCycle(hit)
	
	if hit.Name == "HumanoidRootPart" and hit.Parent:FindFirstChild("Humanoid") and parent:GetAttribute("iscycling") == false then
		parent:SetAttribute("iscycling",true)
		cyclePics()
	end

end

parent.Touched:Connect(startCycle)