How to Debounce properly

Hello!

I am working on a script that seamlessly teleports you when you touch a teleport part. There are two teleport parts, which are identical.

My problem is that I want the the teleport to happen only once and not multiple times (When you touch one of the teleport parts).

My script is supposed to print “Touching” once when touching the part and “TouchEnded” once the touch has ended with the part. Right now it prints both of them multiple times when moving while touching the part.

I also don’t want to use a wait(x) command as that will make teleportation unavailable for x time.

Here is my script:

repeat wait(3) until game:IsLoaded()

local portal1 = workspace.World.Pitfall.portal1.PortalPart
local portal2 = workspace.World.Pitfall.portal2.PortalPart

local plr = game.Players.LocalPlayer
local touchValue = plr:FindFirstChild("canTouch")
touchValue.Value = false

portal1.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid") then
		touchValue.Value = true
		local char = hit.Parent
		local player = game.Players:GetPlayerFromCharacter(char)
		
		print("touching")
		
		if portal1.TouchEnded then
			touchValue.Value = false
			local offset = portal1.CFrame:ToObjectSpace(char.HumanoidRootPart.CFrame)
			--char.HumanoidRootPart.CFrame = portal2.CFrame * offset
			print("TouchEnded")
			wait(1)
		end
	end
end)

portal2.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid") then
		local char = hit.Parent
		local player = game.Players:GetPlayerFromCharacter(char)
		
		print("Touching")
		
		if portal1.TouchEnded then
			touchValue.Value = false
			local offset = portal2.CFrame:ToObjectSpace(char.HumanoidRootPart.CFrame)
			--char.HumanoidRootPart.CFrame = portal1.CFrame * offset
			print("TouchEnded")
			wait(1)
		end
	end
end)
2 Likes

TouchEnded is a functionimagasdase (1)

1 Like

Thank you for pointing that out, i’ll try to fix it.

Is it possible to put the TouchEnded function inside the Touched function?

1 Like

TouchEnded gives the hit parameter aswell, so it is advised to put it outside the function

But yea it is possible

1 Like

TouchEnded is not a function it is an Event which you can connect to a function.

coolyoshi is correct though you can connect a function within a function although you need to ensure you disconnect it after it has been fired or you create multiple connections which will run that code many times.

Example

portal1.Touched:Connect(function(hit)
     local touchEndedConnection = nil
     touchEndedConnection = portal1.TouchEnded:Connect(function(hit)
          touchEndedConnection:Disconnect()
     end)
end)

Let me know if this helps.

With this, do you think I would need the canTouch boolean anymore?

Yes you need a debounce, but currently the canTouch variable isn’t being used as a debounce because its not being checked in your conditional statement.

You also have other inconsistencies in your code like you’re checking portal1 touch ended inside of the portal2 touched connected function

You’re also not changing the value of the canTouch inside of the portal2 func.

Thank you for pointing these out. I have now implemented your changes into my new simplified code that prints touch or notouch when you touch and stop touching a part. It might be me tweaking on this code or there isn’t a reliable way to do what i’m trying to do.

Here is my new code:

repeat wait(1) until game:IsLoaded()

local part = workspace.TouchPart

local plr = game.Players.LocalPlayer
local touchValue = false

part.Touched:Connect(function(hit)
	if not touchValue then
		touchValue = true
		wait()
		print("Touch!")
		local touchEndedConnection = nil
		wait()
		if touchValue then
			touchEndedConnection = part.TouchEnded:Connect(function(hit)
				print("No Touch!")
				touchEndedConnection:Disconnect()
			
			end)
		end
		wait(0.2)
		touchValue = false
	end	
end)

I’m not an advanced scripter yet so my understanding of the script is not 100%.
Thank you for your help, I appreciate it very much.

The wait before the touchValue = false makes it a little better.

The problem still is that if I increase the wait() time to like 5 seconds, then the script will not work until the 5 seconds have passed. I would want to make it so that it wouldn’t print anything if you move while still touching the part.

Right now how it works is if you press A and D quickly on top of the block, it repeats touch and no touch.

Touch events are is very unreliable for humanoids, since, depending on the avatar, there can be multiple parts touching and untouching the portal.

TouchEnded best to be avoided, since from my experience, there is no guarantee that for every Touched event you will get a corresponding TouchEnded event.

Also, even though this is a LocalScript, it will still react to other players avatars, as they are replicated to all clients.

Since you want to avoid teleporting player again, I suggest lock on teleport until player moves away from the other teleport.

local plr = game.Players.LocalPlayer
local debounce = false

portal1.Touched:Connect(function(hit)
	-- first check debounce
	if debounce then return end
	--then check if portal has been hit by a humanoid
	if not hit.Parent:FindFirstChild('HumanoidRootPart') then return end
	--then check if this is an NPC or other player
	if game.Players:GetPlayerFromCharacter(hit.Parent) ~= plr then return end
	--all seems to be ok, set debounce
	debounce = true
	--teleport player
	local offset = portal1.CFrame:ToObjectSpace(char.HumanoidRootPart.CFrame)
	char.HumanoidRootPart.CFrame = portal2.CFrame * offset
	--only release debounce when player moves away from the OTHER teleport
	while (portal2.Position - hit.Parent.HumanoidRootPart.Position).Magnitude < 5 do
		task.wait()
	end
	--player moved away from the other teleport, release debounce
	debounce = false
end)

Copy and paste the same script for the other portal, changing portal2 to portal1 in the while loop.
I put an arbitrary 5 studs distance from teleport to re-activate, feel free to adjust.

Other solution might be a simple timeout, but I think this work better, since player can re-enter the other teleport straight away by moving out and in again.

Hope this helps.

Hey.

This is my current code with the changes you implemented:

repeat wait(3) until game:IsLoaded()

local plr = game.Players.LocalPlayer
local debounce = false
local portal1 = workspace.TouchPart
local portal2 = workspace.TouchPart2

portal1.Touched:Connect(function(hit)
	-- first check debounce
	if debounce then return end
	--then check if portal has been hit by a humanoid
	if not hit.Parent:FindFirstChild('HumanoidRootPart') then return end
	--then check if this is an NPC or other player
	if game.Players:GetPlayerFromCharacter(hit.Parent) ~= plr then return end
	--all seems to be ok, set debounce
	debounce = true
	--teleport player
	local char = hit.Parent
	local offset = portal1.CFrame:ToObjectSpace(char.HumanoidRootPart.CFrame)
	char.HumanoidRootPart.CFrame = portal2.CFrame * offset
	--only release debounce when player moves away from the OTHER teleport
	while (portal2.Position - hit.Parent.HumanoidRootPart.Position).Magnitude < 5 do
		task.wait()
	end
	--player moved away from the other teleport, release debounce
	debounce = false
end)

portal2.Touched:Connect(function(hit)
	-- first check debounce
	if debounce then return end
	--then check if portal has been hit by a humanoid
	if not hit.Parent:FindFirstChild('HumanoidRootPart') then return end
	--then check if this is an NPC or other player
	if game.Players:GetPlayerFromCharacter(hit.Parent) ~= plr then return end
	--all seems to be ok, set debounce
	debounce = true
	--teleport player
	local char = hit.Parent
	local offset = portal2.CFrame:ToObjectSpace(char.HumanoidRootPart.CFrame)
	char.HumanoidRootPart.CFrame = portal1.CFrame * offset
	--only release debounce when player moves away from the OTHER teleport
	while (portal1.Position - hit.Parent.HumanoidRootPart.Position).Magnitude < 5 do
		task.wait()
	end
	--player moved away from the other teleport, release debounce
	debounce = false
end)

Everything seems to work, however there is this bug that makes you teleport between the two parts multiple times.
robloxapp-20240208-1431090.wmv (1.9 MB)

Your teleports seem to be 12x12 size. For this, you need to increase magnitude check to about 7 (from 5), to avoid double teleport.

EDIT: after testing, 7 seems to be too low. 9 works nicely though. This is because humanoid root part is above the teleport.

Shoot, you’re right.

It seems to work pretty well now.

I’ll mark this as the solution, thank you.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.