Small teleporting script bug

When players spawn, the spawn location is in a game area wich triggers this script that teleports them to the next game area:

local gameArea = script.Parent
local teleportPart = workspace.LiveOrDie.Areas.teleport
local Players = game:GetService("Players")

-- Track which players are already being teleported
local debounced = {}

local function teleportPlayer(player)
	if not player.Character then return end
	local hrp = player.Character:FindFirstChild("HumanoidRootPart")
	if not hrp then return end

	-- Get teleportPart size and position
	local size = teleportPart.Size
	local cf = teleportPart.CFrame

	-- Pick a random offset within the X/Z bounds
	local randX = (math.random() - 0.5) * size.X * 0.8 -- 0.8 to keep them inside
	local randZ = (math.random() - 0.5) * size.Z * 0.8

	-- Final position, lifted 3 studs
	local targetPos = (cf * CFrame.new(randX, size.Y / 2 + 3, randZ)).Position

	-- Teleport entire model (safer than just HRP)
	player.Character:PivotTo(CFrame.new(targetPos))
end

local function onTouched(hit)
	local player = Players:GetPlayerFromCharacter(hit.Parent)
	if not player then return end

	-- Debounce per player
	if debounced[player] then return end
	debounced[player] = true

	-- Delay once, not multiple times
	task.delay(7, function()
		if player.Parent then -- still in game
			teleportPlayer(player)
		end
		-- reset debounce so they can trigger again later if needed
		debounced[player] = nil
	end)
end

if gameArea:IsA("BasePart") then
	gameArea.Touched:Connect(onTouched)
else
	warn("GameArea is not a BasePart!")
end

The problem: Sometimes when its 3 or more players the teleporting time is slightly different and one person ends up teleporting back and forth a few times and then ending up outside of the next game area

1 Like

I’m thinking: The problem is that your current debounce is per-player but the Touched event can fire multiple times quickly for the same character.. this may fix that:

local gameArea = script.Parent
local teleportPart = workspace.LiveOrDie.Areas.teleport
local Players = game:GetService("Players")

local debounced = {}

local function teleportPlayer(player)
	if not player.Character then return end
	local hrp = player.Character:FindFirstChild("HumanoidRootPart")
	if not hrp then return end
	local size = teleportPart.Size
	local cf = teleportPart.CFrame
	local randX = (math.random() - 0.5) * size.X * 0.8
	local randZ = (math.random() - 0.5) * size.Z * 0.8
	local targetPos = (cf * CFrame.new(randX, size.Y / 2 + 3, randZ)).Position
	player.Character:PivotTo(CFrame.new(targetPos))
end

local function onTouched(hit)
	local character = hit.Parent
	local player = Players:GetPlayerFromCharacter(character)
	if not player or debounced[character] then return end
	debounced[character] = true
	task.delay(7, function()
		if player.Parent and character.Parent then
			teleportPlayer(player)
		end
		debounced[character] = nil
	end)
end

if gameArea:IsA("BasePart") then
	gameArea.Touched:Connect(onTouched)
end

Tried to stick with most of your logic.. gl

1 Like
  • Try using .TouchEnded instead of wating 7 seconds ( task.delay(7,function() )

  • When you’re using if player.Parent then... you are referencing the Players service

SMALL SNIPPET

local function onTouchEnded(hit)
	local player = Players:GetPlayerFromCharacter(hit.Parent)
	if player then
        task.wait(0.2) -- small delay to avoid player being unmarke too fast
		debounced[player] = nil
	end
end

Hopefully this helps you. If you have any console error please send it over. :smiley:

2 Likes

I’ll get back later and update if this worked or not

Touchend is a headache all on it’s own.. avoid that at all costs.

@ Nova
local debounced = {}
This Is just a server script way of doing a mass debounce. That was just tossed together sticking to your logic, even if it’s a bit off, it is still a great way to handle that.

1 Like

So i think this is working. How do i secure that the players teleport at the same time or closer to the same time

Or is that not possible since they get teleported immideately after joining i think.

Be clear on your point if you say something like this, TouchEnded and Touched are both valid and useful events for simple stuff like teleport on touch.

1 Like

I’m repeating myself again, .Touched is completely fine in his case, it’s not a projectile that is going 20studs/s for it to not detect properly.

xHeptc Start a new subject, and I’ll fully explain why. I was talking about TouchEnded, not Touched.

TouchEnded and Touched have no differences in accuracy, geometry calculation or anything like that, they differ only in states, where one is Ended and one is Began. You’ve got nothing to say

Can you answer the thing i asked earlier today? Is it possible to do so that the players teleport at more similar times? its a very big gap the more players there are who join the game

1 Like

Yes, I’m working on a different question atm, but that is next.
That 7 second thing per player may have held it up. Maybe this will be a better fit for you.

version 2
local gameArea = script.Parent
local teleportPart = workspace.LiveOrDie.Areas.teleport
local Players = game:GetService("Players")

local waiting = {}
local TELEPORT_DELAY = 7
local timerRunning = false

local function teleportPlayer(player)
	if not player.Character then return end
	local hrp = player.Character:FindFirstChild("HumanoidRootPart")
	if not hrp then return end
	local size = teleportPart.Size
	local cf = teleportPart.CFrame
	local randX = (math.random() - 0.5) * size.X * 0.8
	local randZ = (math.random() - 0.5) * size.Z * 0.8
	local targetPos = (cf * CFrame.new(randX, size.Y / 2 + 3, randZ)).Position
	player.Character:PivotTo(CFrame.new(targetPos))
end

local function startTeleportTimer()
	if timerRunning then return end
	timerRunning = true
	task.wait(TELEPORT_DELAY)
	for player in pairs(waiting) do
		if player.Parent then
			teleportPlayer(player)
		end
	end
	waiting = {}
	timerRunning = false
end

local function onTouched(hit)
	local character = hit.Parent
	local player = Players:GetPlayerFromCharacter(character)
	if not player or waiting[player] then return end
	waiting[player] = true
	startTeleportTimer()
end

if gameArea:IsA("BasePart") then
	gameArea.Touched:Connect(onTouched)
end
1 Like

TouchEnded is not very reliable, as in Roblox every time you stop on the trigger it resets. If you don’t account for that, which is pretty much impossible without a lot more scripting, it’s inconsistent. This can be done much more easily and reliably with zones and/or Region3 checks. This is indeed a more stable and manageable approach for detecting when something is inside an area. What part of that is misinformation? Take a break, Batman.

Oh boy, you are worse than I could have imagined.

TouchEnded is event based, meaning the engine fires them instantly on physics contact changes.

Region3 or ZonePlus checks require manual polling (ex: RunService.Heartbeat), which is less efficient and introduces latency and extra complexicty.

Why compute region intersections 60 times per second when engine already gives you physics contact?

Hey! Take a look at debounces

I’m right, please stop.. this isn’t your post and you’re so far off subject it’s getting stupid.
Nova is asking a question marked URGENT. How about you try to help out a bit here.. You seem to have problems with the bigger picture and think you’re here to prove some point no one cares about. I’m going to set you to Block* now.. So nothing you say to me from here will ever matter.. Good luck here on the forums.

This is exactly what people say when they lose an argument, I don’t care if it’s not my post, I will not let you spread lies about Roblox Events to Roblox Developers.

Sure, when I win, suddenly no one cares, maybe you don’t, after all you were the one not knowing the better practice, so I’d understand if YOU don’t care.

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