许多游戏被划分为多个 地点,例如一个有城镇、城堡、地下城和广阔森林的幻想世界。使用 TeleportService 在地点之间、在不同服务器之间,甚至在其他游戏之间传送用户。
传送玩家
要传送玩家,使用 TeleportService:TeleportAsync()。此方法接受三个参数:
- 要传送到的用户的 PlaceId。
- 包含要传送的 Player 实例的数组。
- 一个可选的 TeleportOptions 实例,包含用于 TeleportAsync() 调用的自定义属性。
local Players = game:GetService("Players")local TeleportService = game:GetService("TeleportService")local TARGET_PLACE_ID = 12345678901234 -- 替换为你自己的local playerToTeleport = Players:GetPlayers()[1] -- 获取游戏中的第一个用户TeleportService:TeleportAsync(TARGET_PLACE_ID, {playerToTeleport})
要获取要传送的适当玩家,你可以使用 BasePart.Touched 或 ProximityPrompt.Triggered 事件来获取单个 Player。然后你可以检查玩家是否属于某个团队 (Player.Team) 或派对 (Player.PartyId)。最后,如果你想传送整个小组而不仅仅是个人,可以使用 Team:GetPlayers() 或 SocialService:GetPlayersByPartyId()。
配置安全传送
三个设置处理传送安全性。
| 设置 | 描述 |
|---|---|
| (创建者仪表板) 受众 > 访问设置 > 地点访问控制 | 控制玩家是否可以通过任何游戏加入你游戏中的任何地点,或者必须先加入 起始地点。 |
| (创建者仪表板) 地点 > 访问 > 直接访问控制 | 为非起始地点覆盖你的游戏级 地点访问控制 设置。 |
| (Studio) 文件 > 体验设置 > 安全性 > 允许第三方传送 | 控制从你的游戏到 你不拥有的游戏 的传送。你可以保持此设置为禁用,并仍然在你拥有的已发布游戏之间传送玩家。 |
地点访问控制 控制玩家传送 进入 你的游戏,并且是防止基于传送的漏洞的最关键设置。

如果你选择 完全开放,玩家可以通过任何游戏的传送加入你游戏中的任何地点,包括深层链接、游戏邀请、加入朋友等。
如果你的游戏有多个地点,并且你想让朋友们能够轻松地加入彼此,无论他们在哪个地点,这是一个不错的选择。如果你不选择此选项,尝试在非起始地点加入朋友的玩家将会进入你游戏的起始地点。
如果你选择 限制为同一宇宙,玩家只能通过你游戏内的传送加入非起始地点。此设置允许客户端和服务器发起的传送。
如果你有一款你不想 迁移到安全传送 的遗留游戏,这是一个不错的选择。
如果你选择 仅在宇宙内安全,玩家只能通过在此游戏内发起的服务器传送加入非起始地点。
如果你的游戏有严格的进度系统,在玩家可以访问某些区域之前,这是一个不错的选择。如果你的游戏有一个玩家不应该访问的测试地点,或者仅使用保留服务器的地点,这也是一个不错的选择。
迁移到安全传送
如果你有一款现有的使用客户端传送的游戏,并希望强制要求服务器发起的传送,目标是将所有传送逻辑从客户端脚本移动到服务器脚本:
- 找到所有调用 Teleport() 的客户端脚本。
- 使用 TeleportAsync() 在服务器脚本中重新实现传送。
创建自定义传送屏幕
当用户触发传送时,他们会看到标准的 Roblox 加载屏幕,等待新地点加载。如有需要,你可以通过在客户端调用 TeleportService:SetTeleportGui() 添加一个自定义传送屏幕。
以下示例从 ReplicatedStorage 设置一个自定义的 ScreenGui。ScreenGui 内的任何脚本都 不会 运行。
local TeleportService = game:GetService("TeleportService")local ReplicatedStorage = game:GetService("ReplicatedStorage")local teleportGui = ReplicatedStorage.TeleportGuiTeleportService:SetTeleportGui(teleportGui)
自定义传送选项
你可以通过设置 TeleportOptions 实例并将其传递给 TeleportService:TeleportAsync() 方法来自定义传送,例如 将用户传送到特定服务器 和 在传送中发送用户数据。
传送到特定服务器
要将用户传送到特定服务器,请使用 TeleportOptions 设置目标服务器并将其传递给 TeleportAsync() 方法。如果你未指定服务器,用户将被传送到公共服务器;此列表中第一个用户的信息将用于匹配。
要将用户传送到特定的公共服务器,请将 TeleportOptions.ServerInstanceId 属性设置为有效的实例 ID,这是公共服务器的唯一标识符。
local teleportOptions = Instance.new("TeleportOptions")teleportOptions.ServerInstanceId = targetServerId
要将用户传送到特定的保留服务器,请设置有效的 TeleportOptions.ReservedServerAccessCode,这是进入保留服务器的唯一代码。
local teleportOptions = Instance.new("TeleportOptions")teleportOptions.ReservedServerAccessCode = reservedServerCode
要将用户传送到新的保留服务器,请将 TeleportOptions.ShouldReserveServer 设置为 true。
local teleportOptions = Instance.new("TeleportOptions")teleportOptions.ShouldReserveServer = true
在传送中发送用户数据
在地方之间传送用户会丢弃与该用户相关的任何本地数据。你可以使用以下方法处理地方之间的数据持久性:
要从地方之间发送基本的 非安全 数据,请在传递给 TeleportAsync() 之前调用 TeleportOptions:SetTeleportData()。请不要 使用此方法传递安全数据;数据对客户端可见且未加密。
local teleportData = {randomNumber = RNG:NextInteger(1, 100),}local teleportOptions = Instance.new("TeleportOptions")teleportOptions:SetTeleportData(teleportData)
要在用户传送到新地点后检索所有数据,请使用 Player:GetJoinData() 函数,其返回一个字典,包含一个 TeleportData 键。
local Players = game:GetService("Players")
local function onPlayerAdded(player)
local joinData = player:GetJoinData()
local teleportData = joinData.TeleportData
local randomNumber = teleportData.randomNumber
print(player.Name .. " 以数字 " .. randomNumber .. " 加入")
end
Players.PlayerAdded:Connect(onPlayerAdded)
要仅在客户端检索传送数据,可以使用 TeleportService:GetLocalPlayerTeleportData()。
处理失败的传送
像任何涉及网络请求的 API 调用,传送可能会失败并抛出错误。将它们包裹在保护调用中 (pcall())。一些失败需要重试,特别是涉及保留服务器的失败,因此我们建议在失败时重试若干次。
即使调用成功并且传送启动,它仍然可能在最后一刻失败而不抛出错误,并将用户留在服务器上。当这种情况发生时,会触发 TeleportService.TeleportInitFailed 事件。
以下示例 ModuleScript 返回一个单独的 SafeTeleport 函数,该函数使用重试逻辑在保护调用中传送玩家。它还具有一个 handleFailedTeleport 函数,用于处理调用成功但未发生传送的情况。
local TeleportService = game:GetService("TeleportService")
local ATTEMPT_LIMIT = 5
local RETRY_DELAY = 1
local FLOOD_DELAY = 15
local function SafeTeleport(placeId, players, options)
local attemptIndex = 0
local success, result -- 在循环外定义 pcall 结果,以便稍后可以报告结果
repeat
success, result = pcall(function()
return TeleportService:TeleportAsync(placeId, players, options) -- 在保护调用中传送用户以防止出错
end)
attemptIndex += 1
if not success then
task.wait(RETRY_DELAY)
end
until success or attemptIndex == ATTEMPT_LIMIT -- 如果调用成功,或者达到重试限制,则停止尝试传送
if not success then
warn(result) -- 将失败原因打印到输出
end
return success, result
end
local function handleFailedTeleport(player, teleportResult, errorMessage, targetPlaceId, teleportOptions)
if teleportResult == Enum.TeleportResult.Flooded then
task.wait(FLOOD_DELAY)
elseif teleportResult == Enum.TeleportResult.Failure then
task.wait(RETRY_DELAY)
else
-- 如果传送无效,报告错误而不是重试
error(("无效的传送 [%s]: %s"):format(teleportResult.Name, errorMessage))
end
SafeTeleport(targetPlaceId, {player}, teleportOptions)
end
TeleportService.TeleportInitFailed:Connect(handleFailedTeleport)
return SafeTeleport
SafeTeleport 函数接收与 TeleportAsync() 函数相同的参数。你可以使用以下脚本与 SafeTeleport 函数一起从游戏的任何地方执行传送:
local Players = game:GetService("Players")
local TeleportService = game:GetService("TeleportService")
local ServerScriptService = game:GetService("ServerScriptService")
local SafeTeleport = require(ServerScriptService.SafeTeleport)
local PLACE_TO_TELEPORT_TO = 12345678
local function teleport(touchPart)
local playerToTeleport = game.Players:GetPlayerFromCharacter(touchPart.Parent)
if playerToTeleport then
SafeTeleport(PLACE_TO_TELEPORT_TO, {playerToTeleport})
end
end
script.Parent.Touched:Connect(teleport)