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

Just by touching it, but I don’t want to be able to keep it touched and for the frame to flicker on and off. That’s why I am using wait(), so even if you keep touching it without moving, it would only enable the frame in a given period of time.

The board is on a wall.

Would I do that two times, since I have more than one touch event or just use one in the example?

Furthermore, if I have two does it matter if I introduce two touch events together and then end the two touch_ended events together? Or do I have to end one before I can create a new one again?

I wouldn’t put a function inside a function for this. This is tricky because of touch. If you stop on the object it’s like resetting, as soon as you move it will fire again. So you need flags like a debounce.
Here is the same thing-ish … showing the same thing. Don’t matter how many times it’s touched, it will not fire again until after it has completed.

local flag = true
if touched then
if flag == true then flag = false
– code
wait(n)
flag = true
end
end

Need that just to get a handle on what is getting touched and when.
Now that you have solid testing setup. You can always set up a counter(s) or even a Boolvalue on the Explorer to test off/set for result. Even set up a toggle switch like this.

1 Like

First of all, you should not have 2 .Touched event it is completely unnecessary.

Second of all, from my understandings, you want it so when you touch a part, a gui appears.
But the second time you touch it, the gui disappears, correct?

Yes. The problem I have is when I touch it the first time and wait 5 seconds the frame disappears without me having to touch it the 2nd time. This is without the second .Touch Event but when I include that as well I seem to be getting problems.

I will, however try everybody’s script and see how they all run.

1 Like

That sounds like my script, i knew it was gonna act like that, but to solve your issue, you’re gonna need to do some stuff with .Touch and .TouchEnded.

I can’t create a script right now cuz i’m on vacation.

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