Skip to content

Game

Game is a collection of functions and events related to players in the game, rounds of a game, and team scoring.

Class Functions

Class Function Name Return Type Description Tags
Game.GetLocalPlayer() Player Returns the local player. Client-Only
Game.GetPlayers([table parameters]) Array<Player> Returns a table containing the players currently in the game. An optional table may be provided containing parameters to filter the list of players returned: ignoreDead(boolean), ignoreLiving(boolean), ignoreSpawned(boolean), ignoreDespawned(boolean), ignoreTeams(integer or table of integer), includeTeams(integer or table of integer), ignorePlayers(Player or table of Player), for example: Game.GetPlayers({ignoreDead = true, ignorePlayers = Game.GetLocalPlayer()}). None
Game.FindPlayer(string playerId) Player Returns the Player with the given player ID, if they're currently in the game. Otherwise returns nil. None
Game.FindNearestPlayer(Vector3 position, [table parameters]) Player Returns the Player that is nearest to the given position. An optional table may be provided containing parameters to filter the list of players considered. This supports the same list of parameters as GetPlayers(). None
Game.FindPlayersInCylinder(Vector3 position, number radius, [table parameters]) Array<Player> Returns a table with all Players that are in the given area. Position's z is ignored with the cylindrical area always upright. An optional table may be provided containing parameters to filter the list of players considered. This supports the same list of parameters as GetPlayers(). None
Game.FindPlayersInSphere(Vector3 position, number radius, [table parameters]) Array<Player> Returns a table with all Players that are in the given spherical area. An optional table may be provided containing parameters to filter the list of players considered. This supports the same list of parameters as GetPlayers(). None
Game.StartRound() None Fire all events attached to roundStartEvent. Server-Only
Game.EndRound() None Fire all events attached to roundEndEvent. Server-Only
Game.GetTeamScore(integer team) integer Returns the current score for the specified team. Only teams 0 - 4 are valid. None
Game.SetTeamScore(integer team, integer score) None Sets one team's score. Server-Only
Game.IncreaseTeamScore(integer team, integer scoreChange) None Increases one team's score. Server-Only
Game.DecreaseTeamScore(integer team, integer scoreChange) None Decreases one team's score. Server-Only
Game.ResetTeamScores() None Sets all teams' scores to 0. Server-Only
Game.StopAcceptingPlayers() None Locks the current server instance to stop accepting new players. Note that players already in the process of joining the server will still be accepted, and Game.playerJoinedEvent may still fire for a short period of time after a call to this function returns. Other new players will be directed to a different instance of the game. Server-Only
Game.IsAcceptingPlayers() boolean Returns true if the current server instance is still accepting new players. Returns false if the server has stopped accepting new players due to a call to Game.StopAcceptingPlayers(). None
Game.TransferAllPlayersToGame(string gameId) None Similar to Player:TransferToGame(), transfers all players to the game specified by the passed in game ID. Does not work in preview mode or in games played locally. Server-Only
Game.TransferAllPlayersToGame(CoreGameInfo) None Similar to Player:TransferToGame(), transfers all players to the game specified by the passed in CoreGameInfo. Does not work in preview mode or in games played locally. Server-Only
Game.TransferAllPlayersToGame(CoreGameCollectionEntry) None Similar to Player:TransferToGame(), transfers all players to the game specified by the passed in CoreGameCollectionEntry. Does not work in preview mode or in games played locally. Server-Only
Game.TransferPlayersToGame(string gameId, Array<Player> players) None Similar to Player:TransferToGame(), transfers the specified list of players to the game specified by the passed in game ID. Note that if a party leader is included in the list of players to transfer, the "Play as Party" party setting is ignored, and other party members will only be transferred if also included in the list of players. Does not work in preview mode or in games played locally. Server-Only
Game.TransferPlayersToGame(CoreGameInfo, Array<Player> players) None Similar to Player:TransferToGame(), transfers the specified list of players to the game specified by the passed in CoreGameInfo. Note that if a party leader is included in the list of players to transfer, the "Play as Party" party setting is ignored, and other party members will only be transferred if also included in the list of players. Does not work in preview mode or in games played locally. Server-Only
Game.TransferPlayersToGame(CoreGameCollectionEntry, Array<Player> players) None Similar to Player:TransferToGame(), transfers the specified list of players to the game specified by the passed in CoreGameCollectionEntry. Note that if a party leader is included in the list of players to transfer, the "Play as Party" party setting is ignored, and other party members will only be transferred if also included in the list of players. Does not work in preview mode or in games played locally. Server-Only
Game.TransferAllPlayersToScene(string sceneName, [table parameters]) None Similar to Player:TransferToScene(), transfers all players to the scene specified by the passed in scene name. Does not work in preview mode or in games played locally.
The following optional parameters are supported:
spawnKey (string): Spawns the players at a spawn point with a matching key. If an invalid key is provided, the players will spawn at the origin, (0, 0, 0).
Server-Only
Game.TransferPlayersToScene(string sceneName, Array<Player> players, [table parameters]) None Similar to Player:TransferToScene(), transfers the specified list of players to the scene specified by the passed in scene name. Note that if a party leader is included in the list of players to transfer, the "Play as Party" party setting is ignored, and other party members will only be transferred if also included in the list of players. Does not work in preview mode or in games played locally.
The following optional parameters are supported:
spawnKey (string): Spawns the players at a spawn point with a matching key. If an invalid key is provided, the players will spawn at the origin, (0, 0, 0).
Server-Only
Game.GetCurrentGameId() string Returns the ID of the current game. When called in preview mode, returns nil if the game has not been published, otherwise returns the published game ID. None
Game.GetCurrentSceneName() string Returns the name of the current scene. None

Events

Event Name Return Type Description Tags
Game.playerJoinedEvent Event<Player> Fired when a player has joined the game and their character is ready. When used in client context it will fire off for each player already connected to the server. None
Game.playerLeftEvent Event<Player> Fired when a player has disconnected from the game or their character has been destroyed. This event fires before the player has been removed, so functions such as Game.GetPlayers() will still include the player that is about to leave unless using the ignorePlayers filter within the parameters. None
Game.roundStartEvent Event Fired when StartRound is called on game. None
Game.roundEndEvent Event Fired when EndRound is called on game. None
Game.teamScoreChangedEvent Event<integer team> Fired whenever any team's score changes. This is fired once per team who's score changes. None
Game.postCameraUpdateEvent Event Fired after the camera is updated. It allows Lua code to run after the camera is updated, so a scenario like UI elements positioning themselves to a world location works without a 1 frame lag. None

Examples

Example using:

FindNearestPlayer

In this example, the player who is closest to the script's position is made twice as big. All other players are set to regular size.

function Tick()
    local allPlayers = Game.GetPlayers()
    local nearestPlayer = Game.FindNearestPlayer(script:GetWorldPosition(), {ignoreDead = true})

    for _, player in ipairs(allPlayers) do
        if player == nearestPlayer then
            player:SetWorldScale(Vector3.ONE * 2)
        else
            player:SetWorldScale(Vector3.ONE)
        end
    end
    Task.Wait(1)
end

See also: Game.GetPlayers | CoreObject.GetWorldPosition | Player.SetWorldScale | Vector3.ONE | CoreLua.Tick | Task.Wait


Example using:

FindPlayer

In this example, when a player joins their ID is saved as a variable. Five seconds later, their ID can be used to fetch that player's object. If they are not found it means they have left the game.

local playerId = nil

local function CheckLater()
    local player = Game.FindPlayer(playerId)
    if Object.IsValid(player) then
        print("Player " .. player.name .. " is still here.")
    else
        print("Player with id " .. playerId .. " left the game.")
    end
end

local function OnPlayerJoined(player)
    playerId = player.id

    Task.Spawn(CheckLater, 5)
end

Game.playerJoinedEvent:Connect(OnPlayerJoined)

See also: Task.Spawn | Game.playerJoinedEvent | Object.IsValid | Player.name


Example using:

FindPlayersInCylinder

Searches for players in a vertically infinite cylindrical volume. In this example, all players 5 meters away from the script object are pushed upwards. The search is setup to affect players on teams 1, 2, 3, and 4.

function Tick()
    local playersInRange = Game.FindPlayersInCylinder(script:GetWorldPosition(), 500, {includeTeams = {1, 2, 3, 4}})

    for _, player in ipairs(playersInRange) do
        local vel = player:GetVelocity()
        vel = vel + Vector3.UP * 250
        player:SetVelocity(vel)
    end
    Task.Wait(0.1)
end

See also: CoreObject.GetWorldPosition | Player.GetVelocity | Vector3.UP | CoreLua.Tick | Task.Wait


Example using:

FindPlayersInSphere

Similar to FindPlayersInCylinder(), but the volume of a sphere is considered in the search instead. Also note that the player's center is at the pelvis. The moment that point exits the sphere area the effect ends, as the extent of their collision capsules is not taken into account for these searches.

function Tick()
    local playersInRange = Game.FindPlayersInSphere(script:GetWorldPosition(), 500)

    for _, player in ipairs(playersInRange) do
        local vel = player:GetVelocity()
        vel = vel + Vector3.UP * 250
        player:SetVelocity(vel)
    end
    Task.Wait(0.1)
end

See also: CoreObject.GetWorldPosition | Player.GetVelocity | Vector3.UP | CoreLua.Tick | Task.Wait


Example using:

GetCurrentGameId

IsAcceptingPlayers

StopAcceptingPlayers

TransferAllPlayersToGame

In this example, players can type the command /reboot into chat to send all players to a fresh server instance. It's the same game, just another copy of the server. Before transferring the players, we lock the server with StopAcceptingPlayers(), otherwise some players might reload into the same server instance.

local GAME_ID = Game.GetCurrentGameId()

function OnChatMessage(_, params)
    local message = string.lower(params.message)
    if message == "/reboot" and Game.IsAcceptingPlayers() then
        Game.StopAcceptingPlayers()
        Game.TransferAllPlayersToGame(GAME_ID)
    end
end
Chat.receiveMessageHook:Connect(OnChatMessage)

See also: Chat.receiveMessageHook


Example using:

GetCurrentSceneName

This example shows how to get the name of the current scene that the player is in.

When a player joins the game, the name of the current scene is printed to the Event Log.

local function OnPlayerJoined(player)
    print("Player is in scene: ", Game.GetCurrentSceneName())
end

Game.playerJoinedEvent:Connect(OnPlayerJoined)

See also: Player.TransferToScene


Example using:

GetLocalPlayer

This function can only be called in a client script, as the server does not have a local player. This example prints the names of all players to the upper-left corner of the screen. The local player appears in green, while other player names appear blue. To test this example, place the script under a Client Context. From the point of view of each player, name colors appear different. That's because on each computer the local player is different.

function Tick()
    local allPlayers = Game.GetPlayers()

    for _, player in ipairs(allPlayers) do
        if player == Game.GetLocalPlayer() then
            UI.PrintToScreen(player.name, Color.GREEN)
        else
            UI.PrintToScreen(player.name, Color.BLUE)
        end
    end
    Task.Wait(3)
end

See also: Game.GetPlayers | UI.PrintToScreen | Player.name | Color.GREEN | Task.Wait


Example using:

GetPlayers

This function is commonly used without any options. However, it can be very powerful and computationally efficient to pass a table of optional parameters, getting exactly the list of players that are needed for a certain condition. In this example, when the round ends it prints the number of alive players on team 1, as well as the number of dead players on team 2.

function OnRoundEnd()
    local playersAlive = Game.GetPlayers({ignoreDead = true, includeTeams = 1})
    local playersDead = Game.GetPlayers({ignoreLiving = true, includeTeams = 2})

    print(#playersAlive .. " players on team 1 are still alive.")
    print(#playersDead .. " players on team 2 are dead.")
end
Game.roundEndEvent:Connect(OnRoundEnd)

See also: Game.roundEndEvent | CoreLua.print | Event.Connect


Example using:

GetTeamScore

This example checks the score for all four teams and prints them to the screen. Note: Other than in preview mode, the scores will only appear on screen if the script is placed inside a Client Context.

function Tick()
    local teamA = Game.GetTeamScore(1)
    local teamB = Game.GetTeamScore(2)
    local teamC = Game.GetTeamScore(3)
    local teamD = Game.GetTeamScore(4)

    UI.PrintToScreen("Team A: " .. teamA)
    UI.PrintToScreen("Team B: " .. teamB)
    UI.PrintToScreen("Team C: " .. teamC)
    UI.PrintToScreen("Team D: " .. teamD)
    Task.Wait(2.98)
end

See also: UI.PrintToScreen | Task.Wait | CoreLua.Tick


Example using:

ResetTeamScores

In this example, when the round ends team scores are evaluated to figure out which one is the highest, then all scores are reset.

function OnRoundEnd()
    -- Figure out which team has the best score
    local winningTeam = 0
    local bestScore = -1

    for i = 1, 4 do
        local score = Game.GetTeamScore(i)
        if score > bestScore then
            winningTeam = i
            bestScore = score
        end
    end

    print("Round ended. Team " .. winningTeam .." Resetting scores.")

    -- Prepare for the next round
    Game.ResetTeamScores()
end

Game.roundEndEvent:Connect(OnRoundEnd)

See also: Game.GetTeamScore | CoreLua.print | Event.Connect


Example using:

SetTeamScore

Team scores don't have to represent things such as kills or points--they can be used for keeping track of and displaying abstract gameplay state. In this example, score for each team is used to represent how many players of that team are within 8 meters of the script.

function Tick()
    local pos = script:GetWorldPosition()

    for team = 1, 4 do
        local teamPlayers = Game.FindPlayersInCylinder(pos, 800, {includeTeams = team})
        Game.SetTeamScore(team, #teamPlayers)
    end

    Task.Wait(0.25)
end

See also: Game.FindPlayersInCylinder | CoreObject.GetWorldPosition | CoreLua.Tick | Task.Wait


Example using:

StartRound

EndRound

In this example, when one of the teams reaches a score of 10 they win the round. Five seconds later a new round starts.

local roundCount = 1
local roundRestarting = false

function OnTeamScoreChanged(team)
    local score = Game.GetTeamScore(team)

    if score >= 10 and not roundRestarting then
        Game.EndRound()
        print("Team " .. team .. " wins!")

        roundRestarting = true
        print("5...")
        Task.Wait(1)
        print("4...")
        Task.Wait(1)
        print("3...")
        Task.Wait(1)
        print("2...")
        Task.Wait(1)
        print("1...")
        Task.Wait(1)
        Game.ResetTeamScores()
        Game.StartRound()
        roundCount = roundCount + 1
        roundRestarting = false
        print("Starting new round")
    end
end

Game.teamScoreChangedEvent:Connect(OnTeamScoreChanged)

See also: Game.GetTeamScore | Event.Connect | Task.Wait | CoreLua.print


Example using:

TransferAllPlayersToScene

In this example, after 10 seconds, all players in the game will be transferred to another scene.

This could be useful after the players in game have defeated a boss, they could all be transferred back to the main lobby.

local bossKilled = true -- Set true for testing

-- If bossKilled is true, after 10 seconds transfer all players
-- to the Lobby scene.

if bossKilled then
    Task.Spawn(function()
        Game.TransferAllPlayersToScene("Lobby")
    end, 10)
end

See also: Player.TransferToScene


Example using:

TransferPlayersToGame

FindPlayer

In this example, a trigger is setup as a teleporter that sends players to a random game. If the player entering the trigger is the leader of a party, then the entire party is transferred to the same game.

local TRIGGER = script:GetCustomProperty("Trigger"):WaitForObject()

function OnBeginOverlap(_, player)
    if not player:IsA("Player") then return end

    local destinationGame = GetRandomFeaturedGame()

    if player.isInParty and player.isPartyLeader then
        -- Transfer the whole party
        local partyOfPlayers = {}
        local partyInfo = player:GetPartyInfo()
        for _,playerId in ipairs(partyInfo:GetMemberIds()) do
            local p = Game.FindPlayer(playerId)
            if p then
                table.insert(partyOfPlayers, p)
            end
        end
        Game.TransferPlayersToGame(destinationGame, partyOfPlayers)
    else
        -- Transfer only the player who entered the trigger
        player:TransferToGame(destinationGame)
    end
end

function GetRandomFeaturedGame()
    local collection = CorePlatform.GetGameCollection("featured")
    local rndIndex = math.random(1, #collection)
    local entry = collection[rndIndex]
    return entry
end

TRIGGER.beginOverlapEvent:Connect(OnBeginOverlap)

See also: Player.GetPartyInfo | PartyInfo.GetMemberIds | CorePlatform.GetGameCollection | Trigger.beginOverlapEvent | CoreObjectReference.WaitForObject


Example using:

TransferPlayersToScene

FindPlayersInCylinder

In this example, a group teleporter periodically sends any players who are standing inside of it to another scene. It then spawns a VFX at the location of the teleport, providing feedback to other players who may be watching nearby.

local SCENE_NAME = script:GetCustomProperty("SceneName")
local VFX_TEMPLATE = script:GetCustomProperty("VFX")
local PERIOD = 120 -- Two minutes
local RADIUS = 500 -- 5 meters

while true do
    Task.Wait(PERIOD)
    local pos = script:GetWorldPosition()
    local players = Game.FindPlayersInCylinder(pos, RADIUS)
    if #players > 0 then
        Game.TransferPlayersToScene(SCENE_NAME, players)
        World.SpawnAsset(VFX_TEMPLATE, {position = pos})
    end
end

See also: World.SpawnAsset | CoreObject.GetCustomProperty | Task.Wait


Example using:

playerJoinedEvent

playerLeftEvent

Events that fire when players join or leave the game. Both server and client scripts detect these events. In the following example teams are kept balanced at a ratio of 1 to 2. For example if there are 6 players two of them will be on team 1 and the other four will be on team 2.

local BALANCE_RATIO = 1 / 2
local playerCount = 0
local team1Count = 0
local team2Count = 0

function OnPlayerJoined(player)
    player.team = NextTeam()
end

function OnPlayerLeft(player)
    playerCount = 0
    team1Count = 0
    team2Count = 0

    local allPlayers = Game.GetPlayers()
    for _, p in ipairs(allPlayers) do
        if p ~= player then
            p.team = NextTeam()
        end
    end
end

function NextTeam()
    local team = 1

    if playerCount == 0 then
        team1Count = 1
    elseif team2Count == 0 then
        team2Count = 1
        team = 2
    else
        local ratio = team1Count / team2Count
        if ratio < BALANCE_RATIO then
            team1Count = team1Count + 1
        else
            team2Count = team2Count + 1
            team = 2
        end
    end

    playerCount = playerCount + 1
    return team
end

Game.playerJoinedEvent:Connect(OnPlayerJoined)
Game.playerLeftEvent:Connect(OnPlayerLeft)

See also: Player.team | Game.GetPlayers | Event.Connect


Example using:

postCameraUpdateEvent

In this example, the postCameraUpdateEvent is used over a Tick function as it allows Lua code to run after the camera is updated, which removes the lag from UI elements being positioned to a world location.

-- Client context script
local TARGET = script:GetCustomProperty("Target"):WaitForObject()
local IMAGE = script:GetCustomProperty("Image"):WaitForObject()

local function UpdateImage()
    local pos = UI.GetScreenPosition(TARGET:GetWorldPosition())

    IMAGE.x = pos.x
    IMAGE.y = pos.y
end

-- Uncomment the below code and comment out the postCameraUpdateEvent line to see
-- the difference between the Tick updating the UI compared to the post camera event.
--[[
function Tick()
    UpdateImage()
end
--]]

Game.postCameraUpdateEvent:Connect(UpdateImage)

See also: CoreObjectReference.GetWorldPosition | UI.GetScreenPosition | CoreObject.GetCustomProperty | Event.Connect


Example using:

roundEndEvent

Several operations need to be made when rounds start and end. In this example, when the game ends it transitions to a "round ended" state for three seconds, then respawns all players to spawn points. The advantage of using events is that the different scripts can be separated from each other to improve organization of the project. The condition for ending the round is set here as one team reaching 5 points and can be located in one script. Meanwhile the various outcomes/cleanups can be broken up into different scripts in a way that makes the most sense per game, all listening to the roundEndEvent.

local gameState = "PLAYING"

function OnRoundEnd()
    gameState = "END"

    print("Round ended. Team " .. winningTeam .. " won!")

    -- Waits for 3 seconds then continues
    Task.Wait(3)

    -- Respawn all the players
    local allPlayers = Game.GetPlayers()
    for _, player in ipairs(allPlayers) do
        player:Spawn()
    end

    Game.ResetTeamScores()
    gameState = "LOBBY"
end
Game.roundEndEvent:Connect(OnRoundEnd)

function Tick()
    if gameState == "PLAYING" then
        local scoreObjective = 5

        if Game.GetTeamScore(1) == scoreObjective then
            winningTeam = 1
            Game.EndRound()

        elseif Game.GetTeamScore(2) == scoreObjective then
            winningTeam = 2
            Game.EndRound()
        end
    end
end

See also: Game.EndRound | Player.Spawn | CoreLua.print | Task.Wait | Event.Connect


Example using:

roundStartEvent

Several functions and events in the Game namespace are convenient for controlling the flow of a game. In this example, the game requires two players to join. It begins in a lobby state and transitions to a playing state when there are enough players.

local gameState = "LOBBY"

print("Waiting for 2 players to join...")

function OnRoundStart()
    gameState = "PLAYING"
    print("New round starting...")
end
Game.roundStartEvent:Connect(OnRoundStart)

function Tick()
    if gameState == "LOBBY" then
        -- The condition for starting a round
        local playerCount = #Game.GetPlayers()
        if playerCount >= 2 then
            Game.StartRound()
        end
    end
end

See also: Game.StartRound | CoreLua.print | Event.Connect


Example using:

teamScoreChangedEvent

IncreaseTeamScore

DecreaseTeamScore

In this example, when a player jumps their team gains 1 point and when they crouch their team loses 1 point. The OnTeamScoreChanged function is connected to the event and prints the new score to the Event Log each time they change.

function OnTeamScoreChanged(team)
    local score = Game.GetTeamScore(team)
    print("Score changed for team " .. team .. ", new value = " .. score)
end

Game.teamScoreChangedEvent:Connect(OnTeamScoreChanged)

function HandlePlayerJumped(player)
    Game.IncreaseTeamScore(player.team, 1)
end

function HandlePlayerCrouched(player)
    Game.DecreaseTeamScore(player.team, 1)
end

local playersJumping = {}
local playersCrouching = {}

function Tick()
    local allPlayers = Game.GetPlayers()

    for _, player in ipairs(allPlayers) do
        -- Jump
        if player.isJumping and player.isJumping ~= playersJumping[player] then
            HandlePlayerJumped(player)
        end
        playersJumping[player] = player.isJumping

        -- Crouch
        if player.isCrouching and not player.isJumping and player.isCrouching ~= playersCrouching[player] then
            HandlePlayerCrouched(player)
        end
        playersCrouching[player] = player.isCrouching
    end
end

See also: Game.GetTeamScore | Player.isJumping | CoreLua.print



Last update: February 10, 2023