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)
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.
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.
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)