trying to make a system where upon touching a teleport trigger (which are tagged as “teleportTrigger”), they’re teleported to a part (referenced as an objectvalue called “teleportTo”). since it’s likely that the teleportTo part is also a teleport trigger, i want the game to wait until the player is no longer touching ANY part with the teleportTrigger tag before allowing the player to teleport again.
here’s my code (it currently rapidly teleports the player between parts, which is not what i want):
local collectServ = game:GetService("CollectionService");
local player = game:GetService("Players").LocalPlayer;
local teleportConnections = {};
local isTouchingTrigger = script:WaitForChild("isTouchingTrigger");
local function checkTriggerParts()
local playerParts = {};
local params = OverlapParams.new();
params.FilterDescendantsInstances = {player.Character};
params.FilterType = Enum.RaycastFilterType.Include;
for i, triggerPart in pairs(collectServ:GetTagged("teleportTrigger")) do
local touchingPlayerParts = game.Workspace:GetPartsInPart(triggerPart, params);
for i, v in pairs(touchingPlayerParts) do
table.insert(playerParts, v);
end
end
print(#playerParts);
if #playerParts == 0 then -- if the player is NOT touching any teleport
isTouchingTrigger.Value = false;
end
end
local function handleTrigger(hitPart, triggerPart)
local teleportTo = triggerPart:FindFirstChild("teleportTo"); -- ObjectValue that points to "recipient" part
if isTouchingTrigger.Value == false and teleportTo.Value then -- if you aren't already touching a triggerPart and there is a destination part
if hitPart.Parent.Name == player.Name and player.Character.HumanoidRootPart then -- if the touching part is the player and we have a rootPart
isTouchingTrigger.Value = true; -- we are touching a trigger
local rootPart = player.Character.HumanoidRootPart;
rootPart.CFrame = teleportTo.Value.CFrame + Vector3.new(0, (rootPart.Size.Y*2) + (triggerPart.Size.Y/2), 0); -- set the player's position to the teleportTo
triggerPart.TouchEnded:Wait();
checkTriggerParts()
end
end
end
collectServ:GetInstanceAddedSignal("teleportTrigger"):Connect(function(triggerPart)
teleportConnections[triggerPart] = triggerPart.Touched:Connect(function(hitPart)
handleTrigger(hitPart, triggerPart);
end);
end)
collectServ:GetInstanceRemovedSignal("teleportTrigger"):Connect(function(triggerPart)
teleportConnections[triggerPart]:Disconnect();
end)
for i, triggerPart in pairs(collectServ:GetTagged("teleportTrigger")) do
teleportConnections[triggerPart] = triggerPart.Touched:Connect(function(hitPart)
handleTrigger(hitPart, triggerPart);
end);
end
teleportTo is an object value inside the teleportTrigger part, for reference
I worked up a bit of a loose solution, but it works nonetheless. Probably may need a bit of adjustment with how you want the delay to work.
In summary, it waits for the (what was checkTriggerParts()) to be false before letting them teleport them. I also added a delay for letting them stand off it so they can walk away safely.
local collectServ = game:GetService("CollectionService");
local player = game:GetService("Players").LocalPlayer;
local teleportConnections = {};
local isTouchingTrigger = script:WaitForChild("isTouchingTrigger");
-- Slightly altered checkTriggerParts, returns if there's more than 1 part being touched
local function isTouchingTeleport()
local playerParts = {};
local params = OverlapParams.new();
params.FilterDescendantsInstances = {player.Character};
params.FilterType = Enum.RaycastFilterType.Include;
for i, triggerPart in pairs(collectServ:GetTagged("teleportTrigger")) do
local touchingPlayerParts = game.Workspace:GetPartsInPart(triggerPart, params);
for i, v in pairs(touchingPlayerParts) do
table.insert(playerParts, v);
end
end
--print(#playerParts);
return #playerParts >= 1
end
-- Teleports the player's charcter, parital debounce for
-- letting the player leave the teleporter
local function handleTrigger(hitPart, triggerPart)
local teleportTo = triggerPart:FindFirstChild("teleportTo"); -- ObjectValue that points to "recipient" part
if isTouchingTrigger.Value == false and teleportTo.Value then -- if you aren't already touching a triggerPart and there is a destination part
if hitPart.Parent.Name == player.Name and player.Character.HumanoidRootPart then -- if the touching part is the player and we have a rootPart
isTouchingTrigger.Value = true; -- we are touching a trigger
local rootPart = player.Character.HumanoidRootPart;
rootPart.CFrame = teleportTo.Value.CFrame + Vector3.new(0, (rootPart.Size.Y*2) + (triggerPart.Size.Y/2), 0); -- set the player's position to the teleportTo
-- Partial delay for when they land
delay(0.2, function()
repeat task.wait() until not isTouchingTeleport()
-- Partial delay to let them fully get off
task.wait(0.2)
isTouchingTrigger.Value = false;
end)
end
end
end
collectServ:GetInstanceAddedSignal("teleportTrigger"):Connect(function(triggerPart)
teleportConnections[triggerPart] = triggerPart.Touched:Connect(function(hitPart)
handleTrigger(hitPart, triggerPart);
end);
end)
collectServ:GetInstanceRemovedSignal("teleportTrigger"):Connect(function(triggerPart)
teleportConnections[triggerPart]:Disconnect();
end)
for i, triggerPart in pairs(collectServ:GetTagged("teleportTrigger")) do
teleportConnections[triggerPart] = triggerPart.Touched:Connect(function(hitPart)
handleTrigger(hitPart, triggerPart);
end);
end
local alreadyTeleported = {}
function isPlayer(model)
if model then
local player = game:GetService("Players"):GetPlayerFromCharacter(model)
if player then
return player
end
end
end
local teleporterA = workspace.Teleporters.A
local teleporterB = workspace.Teleporters.B
teleporterA.Touched:Connect(function(hitPart)
local model = hitPart:FindFirstAncestorOfClass("Model")
local player = isPlayer(model)
if player then
if alreadyTeleported[player] then -- prevent player from teleporting if teleported from another part
return
end
alreadyTeleported[player] = true
model:PivotTo(teleporterB.CFrame)
local checkParts:RBXScriptConnection
checkParts = game:GetService("RunService").Heartbeat:Connect(function()
local touchedParts = workspace:GetPartsInPart(teleporterB)
for _,touchPart:BasePart in pairs(touchedParts) do
local model = touchPart:FindFirstAncestorOfClass("Model")
local playerInB = isPlayer(model)
if playerInB == player then
return -- return if has player
end
end
checkParts:Disconnect() -- made it here cuz no return
alreadyTeleported[player] = false
end)
end
end)
teleporterB.Touched:Connect(function(hitPart)
local model = hitPart:FindFirstAncestorOfClass("Model")
local player = isPlayer(model)
if player then
if alreadyTeleported[player] then -- prevent player from teleporting if teleported from another part
return
end
alreadyTeleported[player] = true
model:PivotTo(teleporterA.CFrame)
local checkParts:RBXScriptConnection
checkParts = game:GetService("RunService").Heartbeat:Connect(function()
for _,touchPart:BasePart in pairs(workspace:GetPartsInPart(teleporterA)) do
local model = touchPart:FindFirstAncestorOfClass("Model")
local playerInA = isPlayer(model)
if playerInA == player then
return -- return if has player
end
end
checkParts:Disconnect() -- made it here cuz no return
alreadyTeleported[player] = false
end)
end
end)
function makeTeleporter(teleporterPart, destinationPart)
teleporterPart.Touched:Connect(function(hitPart)
local model = hitPart:FindFirstAncestorOfClass("Model")
local player = isPlayer(model)
if player then
if alreadyTeleported[player] then -- prevent player from teleporting if teleported from another part
return
end
alreadyTeleported[player] = true
model:PivotTo(destinationPart.CFrame) -- teleport player to destination
local checkParts:RBXScriptConnection
checkParts = game:GetService("RunService").Heartbeat:Connect(function()
local touchedParts = workspace:GetPartsInPart(destinationPart)
for _,touchPart:BasePart in pairs(touchedParts) do
local model = touchPart:FindFirstAncestorOfClass("Model")
local playerInB = isPlayer(model)
if playerInB == player then
return -- return if has the same player still inside destination part
end
end
checkParts:Disconnect() -- made it here cuz no return
alreadyTeleported[player] = false
end)
end
end)
end
makeTeleporter(teleporterA, teleporterB)
makeTeleporter(teleporterB, teleporterA)
Feel free to add your own features such as Delay, and OverlapParams for workspace:GetPartsInPart()
this is great!! i was today years old when i found out about delay()
@DudeW0rld also i appreciate your hand in trying out this too :] looks like you went for a server script approach, meanwhile i was going for a localscript approach. i'll keep this in mind in case anything happens!!