Issue with teleporting multiple players

I raised it sufficiently off the ground and set its can collide to false (can touch is still set to true) but still nothing.

also I changed my avatar to the classic “bacon hair” to see if that would fix, as well as closing and reopening studio and still nothing

1 Like

Alright should only be an hour or so more until I can make that workaround

2 Likes

Sorry took a lot longer than expected I’ll check it out now

2 Likes

I think it might be better to create a large part above the pad to act like a zone.
You can then check which player is within the zone and teleport using that data.
This would solve the wonkiness with .Touched checks with characters’ feet.

2 Likes

It would also make sure players are teleported, even if they jump.

2 Likes

Here is a working version of the script, it uses a raycast to check if the player is in the zone, as well as a touched event to see when they first enter (read comments in the code and ask if you need more of an explanation):

local TeleportService = game:GetService("TeleportService")
local teleportID = 14627040487

local circle = script.Parent
local timer = 10
local PlayerTable = {}

circle.Touched:Connect(function(hit)
	--// try to get player
	local plr = game.Players:GetPlayerFromCharacter(hit.Parent) or game.Players:GetPlayerFromCharacter(hit.Parent.Parent)
	if plr and not table.find(PlayerTable, plr) then
		--// This if statement checks if the player was found and if they're not already in the table
		table.insert(PlayerTable, plr) -- adds plr to table
	end
end)

while wait(1) do
	timer -=1
	print(timer)

	--// Check to make sure player is still in the part

	for _, plr in PlayerTable do
		local char = plr.Character
		if not char then continue end

		--// Ray Origin is where the raycast starts
		local RayOrigin = char.PrimaryPart.Position
		local RayDirection = Vector3.new(0, -5, 0) -- -5 on the Y will make the ray go -5 studs down from the origin

		local Params = RaycastParams.new() -- You can make parameters
		Params.FilterType = Enum.RaycastFilterType.Include
		Params.FilterDescendantsInstances = {workspace.TpParts} -- will only hit parts in this folder

		local ray = workspace:Raycast(RayOrigin, RayDirection, Params) -- make the raycast

		if ray then
			local hit = ray.Instance
			if hit then
				print(hit)
				--// The if below will check if the player is still in the circle
				--// if they aren't then they will be removed from the table
				if hit == circle then continue
				else table.remove(PlayerTable, plr) end
			end
		end
	end
	if timer == 0 then 
		timer = 10
		TeleportService:TeleportAsync(teleportID, PlayerTable) --Teleport players
		PlayerTable = {} -- Reset plr table
	end
end

Important
Put the circle part inside a folder in the workspace called TpParts

3 Likes

The problem with this, imo, is that there isn’t a real good way to check when they leave the zone (other than doing something similar to what I did in my script, but then there’s no need for an extra part) because TouchEnded will fire on and off when the player moves inside the part (in my past experiences)

2 Likes

Here’s the thing, you shouldn’t be using .Touched in the first place to check if a part is within another part. I’m pretty sure there is a method in workspace called workspace:GetPartsInPart() which would be better. You can then check if that part belongs to a player and add them to the table, instead of ray casting.

2 Likes

Yes there is a method like this, I have used both this and the GetTouchingParts method in the past both ways were very inconsistent and would basically just detect whenever, which last I checked seem to be a common error. .Touched usually does work (sometimes multiple times but that is why we have a check so we don’t add the player twice) and then to confirm instead of using something like TouchEnded (which would most likely cause mayhem) we use a raycast which should be by far them most accurate

2 Likes

Have you used them on floor pads, or as zones?

2 Likes

Yes actually, i can give a backstory i guess (lol). So I’m making a Super Power Training game (kinda my thing) and I was making training zones.


Iteration 1

  • Method: .Touched and .TouchEnded
  • How: Main pad
  • Result: Sometimes would work, sometimes would stop working while in zone too

Iteration 2 & 3

  • Method: GetTouchingParts & GetPartsInPart
  • How: Main Pad
  • Result: Usually detected nothing

Iteration 4 (Current Day)

  • Method: Raycast (when player uses the tool)
  • How: A zone floor
  • Result: Always works

I also had an issue with the first 3 methods while making a punch tool.

2 Likes

Interesting.
From what I’ve observed, .Touched and .TouchedEnded are events, and only fire when something starts touching or stopped touching a part respectively, not when it is actively touching the part.

:GetTouchingParts() and :GetPartsInPart() returns a table of parts that are essentially inside the other part, and work best when used as a zone.


The red part is the zone to use the getParts method on, not the blue platform.

Raycasting, while it does work for finding parts, is a tad-bit too complicated for something as simple as getting players in a region, requiring that you get a list of players from the .Touched or other functions and then doing the raycast.

I believe the best way to do this would be something like this:

local PlayersService = game:GetService("Players")
local TeleportService = game:GetService("TeleportService")
local teleportID = 14627040487

local zone = script.Parent --// the part encasing the floor pad
local timer = 10
local PlayerTable = {}

while task.wait(1) do
	timer -=1
	print(timer)
	
	if timer == 0 then
		timer = 0
		
		local parts = workspace:GetPartsInPart(zone) --// get the parts inside of the zone
		for _, part in parts do
			local model = part:FindFirstAncestorOfClass("Model") --// check if the character model exists
			if model and model:FindFirstChildOfClass("Humanoid") then --// check if the model has a humanoid
				
				local player = PlayersService:GetPlayerFromCharacter(model) --// check if the character is a player
				if player and table.find(PlayerTable, player) == nil then
					table.insert(PlayerTable,player) --// add them to the table
				end
				
			end
		end
		
		TeleportService:TeleportAsync(teleportID, PlayerTable) --// teleport them
		
		task.wait(1)
		timer = 10 -- restart the cycle
	end
end

I think this is a bit more readable and works all the time from my testing.
Using the image example from above as the test case here.

The way he did it worked well. But I am new to scripting so idk what you two are talking about lol

your script makes more sense to me

Fair enough lol.
Basically, I’m trying to condense down his code into something a bit more readable, so that it’s easier to edit in the future.

There’s nothing wrong with his code though, so you’re free to use whichever you want.

1 Like

ok thanks, yours is a lot easier to read, also quick question what is raycasting?

Ray casting is a method where Roblox iteratively steps along a line until it hits something.
If you’ve ever taken an algebra class, then you should know a ray as a point that goes on forever.

image

Roblox breaks the ray into segments and checks whether the segment hits something.

You can read more about it here: WorldRoot:Raycast()

That’s the gist of it.

oooh okay yeah that makes sense.
Thanks so much for your help, also super quick simple question: there is a surface GUI on a sign in the circle so that you can see how long until teleport, but its not updating when I put text = timer… something about the client server relationship I think

I should probably mention that rays in Roblox aren’t infinite, but you can define how long they are.

Mind showing me a code snippet where you try to update the text on the sign?

local PlayersService = game:GetService("Players")
local TeleportService = game:GetService("TeleportService")
local teleportID = 14627040487
local text = workspace.Text.SurfaceGui.Frame.TextLabel.Text
local zone = script.Parent --// the part encasing the floor pad
local timer = 10
local PlayerTable = {}

while task.wait(1) do
	timer -=1
	print(timer)
	text = timer
	if timer == 0 then
		timer = 0

		local parts = workspace:GetPartsInPart(zone) --// get the parts inside of the zone
		for _, part in parts do
			local model = part:FindFirstAncestorOfClass("Model") --// check if the character model exists
			if model and model:FindFirstChildOfClass("Humanoid") then --// check if the model has a humanoid

				local player = PlayersService:GetPlayerFromCharacter(model) --// check if the character is a player
				if player and table.find(PlayerTable, player) == nil then
					table.insert(PlayerTable,player) --// add them to the table
				end

			end
		end

		TeleportService:TeleportAsync(teleportID, PlayerTable) --// teleport them

		task.wait(1)
		timer = 10 -- restart the cycle
	end
end