Teleport to specific location when arriving from a place within an experience. - How will I do this?

I’m making a theme park game, and each ride is separated into different places within the same experience.

When a player exits that place, they have to touch a part that will teleport them.
But when they arrive at the Start Place, it puts them on the default SpawnPoint.

When I say Start Place, I mean the MAIN place within the entire experience, the one that all players join when they press the green play button on the Roblox page for the game.

What can I use so that it teleports them to a specific point in that Start Place, like a cframe position when they arrive from the other place? Instead of the main default SpawnPoint.

I am not much of a scripter, but I have attempted using TeleportData.

3 Likes

Teleport data

local TeleportService = game:GetService("TeleportService")
local targetPlaceId = 123456789 -- The ID of your Start Place

function teleportPlayer(player)
    local teleportData = {
        arrivalPoint = "SpecificSpawnPoint" -- Identifier for your specific spawn point
    }
    TeleportService:TeleportAsync(targetPlaceId, {player}, teleportData)
end

Step 2: Reading TeleportData Upon Arrival

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

Players.PlayerAdded:Connect(function(player)
    player.CharacterAdded:Connect(function(character)
        local humanoidRootPart = character:WaitForChild("HumanoidRootPart")

        -- Assuming you have a RemoteEvent for receiving teleport data
        local teleportDataEvent = ReplicatedStorage:WaitForChild("TeleportDataEvent")
        
        teleportDataEvent.OnClientEvent:Connect(function(data)
            if data and data.arrivalPoint == "SpecificSpawnPoint" then
                -- Set to the CFrame of the specific point you want
                humanoidRootPart.CFrame = CFrame.new(x, y, z) -- Replace x, y, z with your coordinates
            end
        end)
    end)
end)

Step 3: Sending TeleportData to the LocalScript

local TeleportService = game:GetService("TeleportService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

-- Ensure you have a RemoteEvent named TeleportDataEvent in ReplicatedStorage
local teleportDataEvent = ReplicatedStorage:WaitForChild("TeleportDataEvent")

Players.PlayerAdded:Connect(function(player)
    player.OnTeleport:Connect(function(state, placeId, teleportData)
        if state == Enum.TeleportState.InProgress and teleportData then
            -- Wait until the player's character is loaded to ensure the client script is ready
            player.CharacterAdded:Wait()
            -- Fire the RemoteEvent to the client with the teleport data
            teleportDataEvent:FireClient(player, teleportData)
        end
    end)
end)

You need remote events and replace the Cframe position there

1 Like

According to the Roblox Creator Documentation, the third argument for TeleportService:TeleportAsync() does not accept a standard table.

It only accepts a TeleportOptions object that has been assigned a value with TeleportService:SetTeleportData(). With that function, you can then assign a table to it, and then pass the TeleportOptions through as the third argument for the :TeleportAsync() call.


The rest of the code you posted is generally ok, except for some specific sections, including:

  • In “Step 2”, where it’s unnecessarily connecting OnClientEvent to a new function every single time the player’s Character respawns. Furthermore, given that the server already receives the TeleportOptions in the example code from “Step 3”, there shouldn’t be a need to communicate that to the client since the server could teleport the player’s Character directly to the intended spawnpoint / CFrame right then and there.
  • In “Step 3”, player.OnTeleport is being used to detect when a player arrives from a teleport, but if I understand correctly, after reading the documentation, that event is meant to be used before teleporting a player to a new place:

OnTeleport

Fired when the TeleportState of a player changes. This event is useful for detecting whether a teleportation was successful.

What is the TeleportState?

When a teleportation request is made using TeleportService, there are a series of stages before the Player is teleported. The current stage is represented by the Enum.TeleportState value which is given by OnTeleport. See below for a practical example of this.

The summary of each of the TeleportStates in the documentation further highlight that it’s meant to be used in the context of detecting the current stage of the teleportation process that a player is at, before they have teleported to the new place. For reference, the InProgress stage, which was checked for in the third codeblock you posted, is described on the Roblox Creator Documentation site in the following way:

The teleport is currently in progress. The player usually disconnects and teleports to the destination after this.

With all of this in mind, I don’t think that player.OnTeleport can be used to detect when a player has arrived in a place as a result of a teleport (but since I haven’t tried that before, if I’m wrong about this, I’d be happy to be corrected via a video that showcases it working in a live game).


Recommendations for OP ( @fxsupermaster5791 )

Here’s an example provided on the Roblox Creator Documentation page for Teleporting Between Places - Sending User Data Along with Teleports:

local teleportData = {
    randomNumber = RNG:NextInteger(1, 100);
}

local teleportOptions = Instance.new("TeleportOptions")
teleportOptions:SetTeleportData(teleportData)


For the use case mentioned in the original post, the first example codeblock posted by @RobloxHasTalentR could be modified to make use of that TeleportOptions object:

Example server-sided code (to be included in the place that the player is leaving)

local TeleportService = game:GetService("TeleportService")
local targetPlaceId = 1 -- Place ID here

local function teleportPlayer(player)
    local teleportData = {
        arrivalPoint = "NameOfSpawnPoint"
        -- Or
        arrivalPoint = CFrame.new(0, 0, 0) -- Input desired coordinates

-- Refer to note at the bottom of this example codeblock for more info.
    }

    local teleportOptions = Instance.new("TeleportOptions")
    teleportOptions:SetTeleportData(teleportData)

    TeleportService:TeleportAsync(targetPlaceId, {player}, teleportOptions)
end

-- Call the "teleportPlayer" function when the player needs to be teleported

--[[ 
Note: If the player needs to be teleported to a completely
unique spawnpoint depending on the ride from the theme park that
they are exiting, this should probably be restructured so that you don't have
to duplicate the script over and over for each exit. Instead, all the intended
spawnpoints / CFrames could be kept in a single table (in a module, perhaps),
and then referenced from there. For a simple, smaller-scale solution, though,
including the example code above in individual scripts should suffice.
--]]

(Note that there’s also TeleportService:TeleportToSpawnByName(), which could be used to specify the name of the SpawnLocation that the player’s Character should be moved to upon teleporting the player to the new place, but the documentation recommends TeleportService:TeleportAsync(), instead, due to its robust functionality).


When detecting when players are arriving from a teleport in the new server, there are 2 main options that I am currently aware of:

Client-sided option

  • TeleportService.LocalPlayerArrivedFromTeleport – This event would fire on the client-side when the player arrives in the place as a result of the teleport. However, in the case of needing to retrieve the TeleportOptions, the documentation recommends the following:

When fetching teleportData and the customLoadingScreen you are advised to use TeleportService:GetLocalPlayerTeleportData() and TeleportService:GetArrivingTeleportGui() instead. This is because these functions can be called immediately without having to wait for this event to fire.

Server-sided option


Since you specifically mentioned that you wanted to teleport them to a CFrame upon arrival, I’ll structure the example code below in a way that checks for that as the incoming data rather than the name of a spawnpoint.

Example server-side code (to be included in the place that the player is arriving at, as a result of the teleport)

local Players = game:GetService("Players")

local function checkForTeleportData(player, Character)
    local joinData = player:GetJoinData()
    local teleportData = joinData["TeleportData"]

    if teleportData ~= nil then

        local arrivalPoint = TeleportData["arrivalPoint"]
        if arrivalPoint ~= nil then
            Character:PivotTo(arrivalPoint)
        end

    end

    return false
end

local function onPlayerJoin(player)
    local firstTimeJoin = true

    if player.Character then
        local returnValue = checkForTeleportData(player, player.Character)
        firstTimeJoin = returnValue
    end

    player.CharacterAdded:Connect(function(Character)
        if firstTimeJoin == true then
            local returnValue = checkForTeleportData(player, Character)
            firstTimeJoin = returnValue
        end

        --[[ Any other relevant code that you would want to run every time the
        player's Character respawns would go here. --]]
    end)
end

for _, player in Players:GetPlayers() do
    task.spawn(onPlayerJoin, player)
end

Players.PlayerAdded:Connect(onPlayerJoin)

Hopefully all of this made sense; if you have any questions, feel free to ask and I’ll try to explain it more.

2 Likes

I know I’m late, but I’m kind of having the same situation here. What kind of scripts should the code be and where should each of them be inserted? (I don’t have much scripting knowledge, by the way)

1 Like

All of the code is intended to be run on the server-side (since that is where Scripts have the authority to make changes that can be visible to all players in the game), which means that the code can be placed in a standard Script that has its RunContext property either set to the default of “Legacy” or “Server”.

  • When the RunContext is set to “Legacy”, the code within the Script can only run in certain places of the game (such as the Workspace and ServerScriptService) but if it’s set to “Server”, it can run in all containers that the server has access to (such as the ReplicatedStorage, ServerStorage, etc.)

The placement of each Script in the game doesn’t matter too much as long as it’s in a place where its code will be able to run. However, for organization purposes, I would recommend placing each one in the ServerScriptService.


Summary

In the game that the player is leaving

local TeleportService = game:GetService("TeleportService")
local targetPlaceId = 1 -- Place ID here

local function teleportPlayer(player)
    local teleportData = {
        arrivalPoint = "NameOfSpawnPoint"
        -- Or
        arrivalPoint = CFrame.new(0, 0, 0) -- Input desired coordinates

-- Refer to note at the bottom of this example codeblock for more info.
    }

    local teleportOptions = Instance.new("TeleportOptions")
    teleportOptions:SetTeleportData(teleportData)

    TeleportService:TeleportAsync(targetPlaceId, {player}, teleportOptions)
end

-- Call the "teleportPlayer" function when the player needs to be teleported

--[[ 
Note: If the player needs to be teleported to a completely
unique spawnpoint depending on the ride from the theme park that
they are exiting, this should probably be restructured so that you don't have
to duplicate the script over and over for each exit. Instead, all the intended
spawnpoints / CFrames could be kept in a single table (in a module, perhaps),
and then referenced from there. For a simple, smaller-scale solution, though,
including the example code above in individual scripts should suffice.
--]]

In the game that the player is being teleported to

local Players = game:GetService("Players")

local function checkForTeleportData(player, Character)
    local joinData = player:GetJoinData()
    local teleportData = joinData["TeleportData"]

    if teleportData ~= nil then

        local arrivalPoint = TeleportData["arrivalPoint"]
        if arrivalPoint ~= nil then
            Character:PivotTo(arrivalPoint)
        end

    end

    return false
end

local function onPlayerJoin(player)
    local firstTimeJoin = true

    if player.Character then
        local returnValue = checkForTeleportData(player, player.Character)
        firstTimeJoin = returnValue
    end

    player.CharacterAdded:Connect(function(Character)
        if firstTimeJoin == true then
            local returnValue = checkForTeleportData(player, Character)
            firstTimeJoin = returnValue
        end

        --[[ Any other relevant code that you would want to run every time the
        player's Character respawns would go here. --]]
    end)
end

for _, player in Players:GetPlayers() do
    task.spawn(onPlayerJoin, player)
end

Players.PlayerAdded:Connect(onPlayerJoin)