Wait() for every time the Touch Functions are Called; not working properly [SOLVED]

  1. Use :Disconnect to disconnect the Touched event after it’s fired. [Not necessary, but can be good].
    Example:
local connection
connection = script.Parent.Touched:Connect(function(Object)
     ---code
end)

task.wait(5)
connection:Disconnect()
--You can disconnect functions within themselves too.
  1. Use task.wait instead of wait.
  2. Why are you using 2 Touched events and 2 while loops? I can smell the issues it could do.
2 Likes

I was using two because one is the first touch when it is enabled, and the second touch is when it is disabled. Then it loops again for the first one and vice versa.

It seems like I do not need the extra event, but that was what I was wondering.

Edit: @Valkyrop,I think the problem is, is when I disconnect the .Touched Event afterwards, the frame still automatically disables. However, not only that but the whole event then only runs once because I have disconnected it. Then I can’t enable it again.

Ok i’ll try to make a script of some form
Uhh something like this maybe?:
I tried making it simple

Local perms = false —i had no name for this, ——basicly what it does is when you leave the part it enabled the option to disable the gui
Local debounce = false
Part.touched:connect(function()

if not debounce then
debounce = true

Gui.enabled = true

if perms then
perms = false
Gui.enabled = false

end
end
debounce = false
end)

Part.touchEnded:connect(function()
if Gui.Enabled == false then
perms = false
else
perms = true
end)

Edit: I realized that this will only work the first time and the the gui will never open again,
Its also getting late for me, so i’ll not be able to help, have a nice day.

Edit 2: Because it works the first time, you could create some sort of ”loop” if you know what i mean. Like when the gui has appeared and then dissapeared it goes back to the orginal status.

1 Like

I think I am still getting the same issues. First time I turn it on, 5 seconds later it disables again.

Thanks for the tip!

Is ‘debounce’ the same as ‘perms’ in your example?

The code provided will create a new while loop every time anything touches the part, including the baseplate/another part/players. Also, Touched events need a debounce otherwise they can run many, many times in a short amount of time. Instead of using wait() since it’s known to be very inaccurate, it’s best to use an end point in time. As others have said, that code can also lead to memory leaks which will eventually lag your game. Don’t worry, I recycled some of my code so you can use as a reference :).

If you need a lot of touched Events that all use the same code, then I suggest doing something like this so it’s very easy to read and :Disconnect the touched events:

local touchedConnections = {}
local partsThatFireTouched = {
	--Put anything you want a touched event for in here
	game.Workspace:WaitForChild("Part1"), game.Workspace:WaitForChild("Part2"), game.Workspace:WaitForChild("Part3")
}

local function PerformHit(hit, partInstance)
	if DateTime.now().UnixTimestampMillis >= touchedConnections[partInstance.Name].TimeForResume then
		--Touched Event is allowed to fire again
		--You can filter this if you need different actions for different parts
		
		--Reset the timer for 5 seconds from now:
		touchedConnections[partInstance.Name].TimeForResume = DateTime.now().UnixTimestampMillis + 5000 --> 5000 milliseconds(5 seconds)
		if partInstance.SurfaceGui.Enabled then
			partInstance.SurfaceGui.Enabled = false
		else
			partInstance.SurfaceGui.Enabled = true
		end
		--return true if you need to disconnect this touched event
	end
end


local function ConnectTouched()
	for i, partInstance in pairs(partsThatFireTouched) do
		--Create a function for the part being touched and store it within its own key within the touchedConnections table
		touchedConnections[partInstance.Name] = {
			TimeForResume = 0; --> handles the very first call
			ConnectionFunction = function(hit)
				if hit.Parent:FindFirstChild("Humanoid") then
					--Only runs if whatever hit it has a humanoid. Be aware this will run for NPCs with humanoids and EVERY player
					local needsToDisconnect = PerformHit(hit, partInstance)
					if needsToDisconnect then
						--If you only ever need for this connection to fire once, then you should include: return true in the PerformHit area
						touchedConnections[partInstance.Name].Connection:Disconnect() --Disconnect RBX event signal
						touchedConnections[partInstance.Name] = nil --Clear memory since we don't need this anywmore
					end
				end
			end;
		}
		--This stores the connection within that part's key and name it connection so we can :Disconnect() it later
		touchedConnections[partInstance.Name].Connection = partInstance.Touched:Connect(touchedConnections[partInstance.Name].ConnectionFunction)
	end
end

local function ClearAllConnections()
	--If you ever need to clear ALL connections (like a game reset or something)
	for partName, connectionTable in pairs(touchedConnections) do
		connectionTable.Connection:Disconnect()
		touchedConnections[partName] = nil
	end
end

ConnectTouched()

I tried to add comments in the code that explains what it does, but basically this code never yields like wait() does. Instead of waiting 5 seconds, this code checks a debounce every time a player actively collides with the part. The debounce is nothing more than setting a very accurate timer for 5 seconds into the future. The added benefit is each one of these connections operate independently from one another since their TimeForResume values are specific to that part. Hope this helped ya out!

[EDIT] Grammar/Deleted a lot of whitespace

3 Likes

What is the meaning behind creating more while loops?

Every time anything touches this part a new while loop will be created.

[EDIT]
If 10 objects touch the part, then there will be 10 while loops running at the same time.

I only need my code to activate when a player who has a certain tool, who touches the object has the ability to enable and disable the SurfaceGui or frame through the player.

Edit: To try and clear any confusion, this is the type of code I currently have so far which works best. However, I think it still disables it after a few seconds automatically though:

script.Parent.Touched:Connect(function(marker)
			if marker ~= nil and marker.Parent ~= nil and marker.Parent:FindFirstChild("CardNumber") ~= nil and marker.Parent.CardNumber.Value == 55 then
				copy.Enabled = true
			    copy.ImageButton.LocalScript.Disabled = false
				task.wait(5)
				if marker ~= nil and marker.Parent ~= nil and marker.Parent:FindFirstChild("CardNumber") ~= nil and marker.Parent.CardNumber.Value == 55 then
					copy.Enabled = false
					copy.ImageButton.LocalScript.Disabled = true
					task.wait(5)
				else
					copy.Enabled = false
				    copy.ImageButton.LocalScript.Disabled = true
				end

My post was only meant as a reference point to solve all the issues mentioned. If you only want to show the gui if the local player is holding a specific tool, then I suggest creating the touched connections ConnectTouched() whenever the player is holding the tool. Then call ClearAllConnections when the player stops holding the tool.

As far as only allowing the the local player to change the surfacegui, we can just add a few lines of code at the top:

local players = game:GetService("Players")
local LocalPlayer = players.LocalPlayer

and add a filter inside the ConnectionFunction that first checks for the humanoid, then checks to see if it is the local player:

local function ConnectTouched()
	for i, partInstance in pairs(partsThatFireTouched) do
		touchedConnections[partInstance.Name] = {
			TimeForResume = 0;
			ConnectionFunction = function(hit)
				local humanoid = hit.Parent:FindFirstChild("Humanoid")
				if humanoid then
					local player = players:GetPlayerFromCharacter(humanoid.Parent)
					if player and player.UserId == LocalPlayer.UserId then
						--It's the local player
						local needsToDisconnect = PerformHit(hit, partInstance)
						if needsToDisconnect then
							touchedConnections[partInstance.Name].Connection:Disconnect()
							touchedConnections[partInstance.Name] = nil
						end
					end
				end
			end;
		}
		touchedConnections[partInstance.Name].Connection = partInstance.Touched:Connect(touchedConnections[partInstance.Name].ConnectionFunction)
	end
end

I wouldn’t use this as it’s several years old, new solutions are available, namely the spatial query API

Ok i changed the script many times but i think this will work:
Also “perms” is meant to make the gui dissapear when you touch it for the second time(i had no good name sorry)


local perms = false -—i had no name for this,  basically what it does is when you leave the part it enabled the option to disable the gui
local debounce = false
script.Parent.touched:connect(function(hit)
if hit.Parent:FindFirstChildWhichIsA(“Humanoid”) then

if not debounce then
debounce = true

if perms then
SurfaceGui.Enabled = false
else
SurfaceGui.Enabled = true

end
end
debounce = false
end
end)

script.Parent.TouchEnded:connect(function()
if SurfaceGui.Enabled == false then
perms = false
else
perms = true
end
end)

1 Like

One of the problems currently, is that I am copying the SurfaceGui from Workspace and putting it into PlayerGui in the script. Since I can still reference it in the same script, I am currently detecting it in a Script and not a Localscript.

Should I try it in a separate LocalScript, or keep it in the same Script?

Edit: Also, there is a lot of stuff that says it is “unknown”.

Should I try and use one debounce, or use debounce and perms?

U should use only one.
And perms is not the same as debounce it’s very different. I explained that in my script.

1 Like

Heres some working code:

local cooldown = os.clock()
script.Parent.Touched:Connect(function()
    if os.clock() - cooldown >= 5 then cooldown = os.clock() else return end

    if SurfaceGui.Enabled then
        -- Do stuff
        SurfaceGui.Enabled = false
    else
        -- Do stuff
        SurfaceGui.Enable = true
    end
end)

No need to use wait or anything lik tht, in fact I hate the usage of wait and try to limit its usage as much as possible.

@Herbz_Dev2106 lmk if it worked.

1 Like

Hmm…it still goes disabled after a couple of seconds, once I have touched the board once.

I know using an extra .Touch event might not be the best way to do this, so what could I do instead that would work better?

Even when I add the extra .Touch event, the first and second touch works. But the cycle doesn’t loop though and I have tried using a while wait(5) do loop. The problem is is that it doesn’t really work properly each time and when I touch it for the 3rd 4th time for example, the .Touch no longer works.

@Herbz_Dev2106 Have you tried my script? Cuz i think it will work.

1 Like
local cooldown = os.clock()

script.Parent.Touched:Connect(function(hitPart)
    if not hitPart.Parent:FindFirstChildWhichIsA("Humanoid") then return end

    if os.clock() - cooldown >= 5 then cooldown = os.clock() else return end

    if SurfaceGui.Enabled then
        -- Do stuff
        SurfaceGui.Enabled = false
    else
        -- Do stuff
        SurfaceGui.Enable = true
    end
end)

Just realized that any object can trigger the .Touched event lol.

@Herbz_2106 Lmk if this works :slight_smile:

I think it enables, but it doesn’t disable afterwards. At least for me anyways.