Creating a timeout system which doesn't affect my loop

I’m making a system so you have to press the buttons that appear on the screen,

However I don’t want to make it really easy for the user. How can I make a timeout system that will fadeout the frame amongst other things that does not effect the loop that I use to spawn the GUIs continuously.

coroutine.wrap(function()
	wait(3) -- fade timeout
	
	-- fade out frame script
end)()

The coroutine won’t pause the loop

Hello!

You can use a Roblox service Debris, which automatically destroys objects after a set period of time this way:

Debris:AddItem(chosen item, time in seconds)

BUT, you also have (maybe even better) alternative ways to do this.
Especially if you have GUIs already set in advance and only change their visibility, you don’t have to destroy instances at all. Perhaps use BindableEvents (which are similar to RemoteEvents, except they are intended for communication between scripts, running on the same machine). So you would have one main script running, and each of your GUIs would contain one script which would listen to these events and be activated when they are called (to save you the work, write code with OOP programming, one main module script and simplicity in mind). When working with this many independent GUIs, you can use so called tagging.
You could also have a coroutine running, like @heII_ish suggested (read the API here and a useful guide here). I would only be concerned about the big number of “accumulated” dead coroutines.

Correct me if I’m wrong, but I thought the garbage collector takes care of coroutines that finished running

1 Like

You could do something like this, incorporating @DevTestDummy’s idea with BindableEvents to some extent:

local timeout = 5 -- Change value here

function CreateButton()
   local eventHandler = Instance.new("BindableEvent")

   local button = Instance.new("TextButton") or your.TextButton:Clone()
   button.Name = "ClickMe"
   -- Set properties here
   button.Parent = YourUIContainer
   
   delay(timeout, function()
      if eventHandler then
         eventHandler:Fire("timeout")
      end
   end)

   local buttonClickConnection = button.MouseButton1Click:Connect(function()
       eventHandler:Fire("clicked")
   end)

   eventHandler.Event:Connect(function(source)
       buttonClickConnection:Disconnect()
       eventHandler:Destroy()
       if source == "timeout" then
            -- the time is up! Fade out the button
       elseif source == "clicked" then
           -- the person clicked on time! Do whatever you want here.
       end
       button:Destroy()
   end)
end

Note that you can add other events too, such as if the player clicked with the right mouse, or you want to listen to when the round is over, etc. The argument you pass on Fire can be used to determine which occurred first, the timeout or the player pressing the button.

1 Like

Yep, I’m also quite inclined to agree. Even if the coroutine doesn’t finish the garbage collector knows its at an unreachable state and cleans it up. Well, this is true for Lua 5.1, so I’m assuming the same logic applies here.

@AbiZinho and @heII_ish I was not sure about the garbage collector, as I was not so “up to date” on coroutine area. Even though there is obviously always some untracked data left, garbage collector tends to be pretty efficient, so I guess this would be a good solution. Thanks for informing me! :slightly_smiling_face:

Hey! Sorry for the delayed response! I’ll try these things out today!