Skip to content

Player

Player is an object representation of the state of a player connected to the game, as well as their avatar in the world. Player also implements the Damageable interface.

Properties

Property Name Return Type Description Tags
name string The Player's name. Read-Write
id string The unique id of the Player. Consistent across sessions. Read-Only
team integer The number of the team to which the Player is assigned. By default, this value is 255 in FFA mode. Read-Write
animationStance string Which set of animations to use for this Player. See Animation Stance Strings for possible values. Read-Write
activeEmote string Returns the id of the emote currently being played by the Player, or nil if no emote is playing. Read-Only
currentFacingMode FacingMode Current mode applied to player, including possible overrides. Possible values are FacingMode.FACE_AIM_WHEN_ACTIVE, FacingMode.FACE_AIM_ALWAYS, and FacingMode.FACE_MOVEMENT. See desiredFacingMode for details. Read-Only
desiredFacingMode FacingMode Which controls mode to use for this Player. May be overridden by certain movement modes like MovementMode.SWIMMING or when mounted. Possible values are FacingMode.FACE_AIM_WHEN_ACTIVE, FacingMode.FACE_AIM_ALWAYS, and FacingMode.FACE_MOVEMENT. Read-Write, Server-Only
defaultRotationRate number Determines how quickly the Player turns to match the camera's look. Set to -1 for immediate rotation. Currently only supports rotation around the Z-axis. Read-Write, Server-Only
currentRotationRate number Reports the real rotation rate that results from any active mechanics/movement overrides. Read-Only
hitPoints number Current amount of hit points. Read-Write
maxHitPoints number Maximum amount of hit points. Read-Write
kills integer The number of times the player has killed another player. Read-Write
deaths integer The number of times the player has died. Read-Write
stepHeight number Maximum height in centimeters the Player can step up. Range is 0-100. Default = 45. Read-Write
maxWalkSpeed number Maximum speed while the player is on the ground. Clients can only read. Default = 640. Read-Write
maxAcceleration number Max Acceleration (rate of change of velocity). Clients can only read. Default = 1800. Acceleration is expressed in centimeters per second squared. Read-Write
brakingDecelerationFalling number Deceleration when falling and not applying acceleration. Default = 0. Read-Write
brakingDecelerationWalking number Deceleration when walking and movement input has stopped. Default = 1000. Read-Write
brakingDecelerationFlying number Deceleration when flying and movement input has stopped. Default = 600. Read-Write
groundFriction number Friction when walking on ground. Default = 8.0 Read-Write
brakingFrictionFactor number Multiplier for friction when braking. Default = 0.6. Read-Write
walkableFloorAngle number Max walkable floor angle, in degrees. Clients can only read. Default = 44. Read-Write
maxJumpCount integer Max number of jumps, to enable multiple jumps. Set to 0 to disable jumping. Read-Write
shouldFlipOnMultiJump boolean Set to false to disable flip animation when player performs double-jump, triple-jump, etc. Defaults to true, enabling flip animation. Read-Write
jumpVelocity number Vertical speed applied to Player when they jump. Default = 900. Speed is expressed in centimeters per second. Read-Write
gravityScale number Multiplier on gravity applied. Default = 1.9. Read-Write
maxSwimSpeed number Maximum speed while the player is swimming. Default = 420. Read-Write
maxFlySpeed number Maximum speed while the player is flying. Default = 600. Read-Write
touchForceFactor number Force applied to physics objects when contacted with a Player. Default = 1. Read-Write
isCrouchEnabled boolean Turns crouching on/off for a Player. Read-Write
mass number Gets the mass of the Player. Read-Only
isAccelerating boolean True if the Player is accelerating, such as from input to move. Read-Only
isCrouching boolean True if the Player is crouching. Read-Only
isFlying boolean True if the Player is flying. Read-Only
isGrounded boolean True if the Player is on the ground with no upward velocity, otherwise false. Read-Only
isJumping boolean True if the Player is jumping. Read-Only
isMounted boolean True if the Player is mounted on another object. Read-Only
isSwimming boolean True if the Player is swimming in water. Read-Only
isWalking boolean True if the Player is in walking mode. Read-Only
isDead boolean True if the Player is dead, otherwise false. Read-Only
isSpawned boolean True if the player is in a spawned state, false if the player is despawned. Read-Only
spawnMode SpawnMode Specifies how a start point is selected when a player initially spawns or spawns from a despawned state. Read-Write
respawnMode RespawnMode Specifies how a start point is selected when a player respawns. Read-Write
respawnDelay number The delay in seconds from when a player dies until they respawn. Read-Write
respawnTimeRemaining number The number of seconds remaining until the player respawns. Returns 0 if the player is already spawned. Read-Only, Server-Only
isVisible boolean Defaults to true. Set to false to hide the player and any attached objects which are set to inherit visibility. Note that using this property in conjunction with the deprecated SetVisibility() function may cause unpredictable results. Server-Only, Read-Write
isCollidable boolean Defaults to true. Set to false to disable collision on the player and any attached objects set to inherit collision. Read-Write
isMovementEnabled boolean Defaults to true. Set to false to disable player movement. Unlike movementControlMode, which can disable movement input, setting isMovementEnabled to false freezes the Player in place, ignoring gravity and reactions to collision or impulses, unless the Player's transform is explicitly changed or the Player is attached to a parent CoreObject that moves. Read-Write
movementControlMode MovementControlMode Specify how players control their movement. Clients can only read. Default: MovementControlMode.LOOK_RELATIVE. MovementControlMode.NONE: Directional movement input is ignored. MovementControlMode.LOOK_RELATIVE: Forward movement follows the current player's look direction. MovementControlMode.VIEW_RELATIVE: Forward movement follows the current view's look direction. MovementControlMode.FACING_RELATIVE: Forward movement follows the current player's facing direction. MovementControlMode.FIXED_AXES: Movement axis are fixed. Read-Write
lookControlMode LookControlMode Specify how players control their look direction. Default: LookControlMode.RELATIVE. LookControlMode.NONE: Look input is ignored. LookControlMode.RELATIVE: Look input controls the current look direction. LookControlMode.LOOK_AT_CURSOR: Look input is ignored. The player's look direction is determined by drawing a line from the player to the cursor on the Cursor Plane. Read-Write
lookSensitivity number Multiplier on the Player look rotation speed relative to cursor movement. This is independent from user's preferences, both will be applied as multipliers together. Default = 1.0. Read-Write, Client-Only
spreadModifier number Modifier added to the Player's targeting spread. Read-Write
currentSpread number Gets the Player's current targeting spread. Read-Only, Client-Only
buoyancy number In water, buoyancy 1.0 is neutral (won't sink or float naturally). Less than 1 to sink, greater than 1 to float. Read-Write
canMount boolean Returns whether the Player can manually toggle on/off the mount. Read-Write, Server-Only
shouldDismountWhenDamaged boolean If true, and the Player is mounted they will dismount if they take damage. Read-Write, Server-Only
isVisibleToSelf boolean Set whether to hide the Player model on Player's own client, for sniper scope, etc. Read-Write, Client-Only
parentCoreObject CoreObject If the Player has been attached to a parent CoreObject, returns that object. Otherwise returns nil. Read-Only
occupiedVehicle Vehicle Returns the Vehicle that the player currently occupies, or nil if the player is not occupying a vehicle. Read-Only
isInParty boolean Returns whether this player is in a party. This is known regardless of if the party is public or private. Read-Only
isPartyLeader boolean Returns whether this player is the leader of a public party. Read-Only

Functions

Function Name Return Type Description Tags
GetWorldTransform() Transform The absolute Transform of this player. None
SetWorldTransform(Transform) None The absolute Transform of this player. Server-Only
GetWorldPosition() Vector3 The absolute position of this player. None
SetWorldPosition(Vector3) None The absolute position of this player. Server-Only
GetWorldRotation() Rotation The absolute rotation of this player. None
SetWorldRotation(Rotation) None The absolute rotation of this player. Server-Only
GetWorldScale() Vector3 The absolute scale of this player. None
SetWorldScale(Vector3) None The absolute scale of this player (must be uniform). Server-Only
AddImpulse(Vector3) None Adds an impulse force to the Player. Server-Only
GetVelocity() Vector3 Gets the current velocity of the Player. The velocity vector indicates the direction, with its magnitude expressed in centimeters per second. None
SetVelocity(Vector3) None Sets the Player's velocity to the given amount. The velocity vector indicates the direction, with its magnitude expressed in centimeters per second. Server-Only
ResetVelocity() None Resets the Player's velocity to zero. Server-Only
GetAbilities() Array<Ability> Array of all Abilities assigned to this Player. None
GetEquipment() Array<Equipment> Array of all Equipment assigned to this Player. None
ApplyDamage(Damage) None Damages a Player. If their hit points go below 0 they die. Server-Only
Die([Damage]) None Kills the Player. They will ragdoll and ignore further Damage. The optional Damage parameter is a way to communicate cause of death. Server-Only
DisableRagdoll() None Disables all ragdolls that have been set on the Player. Server-Only
SetVisibility(boolean, [boolean]) None This function is deprecated. Please use the .isVisible property instead. Shows or hides the Player. The second parameter is optional, defaults to true, and determines if attachments to the Player are hidden as well as the Player. Server-Only, Deprecated
GetVisibility() boolean Returns whether or not the Player is hidden. None
EnableRagdoll([string socketName, number weight]) None Enables ragdoll for the Player, starting on socketName weighted by weight (between 0.0 and 1.0). This can cause the Player capsule to detach from the mesh. All parameters are optional; socketName defaults to the root and weight defaults to 1.0. Multiple bones can have ragdoll enabled simultaneously. See Socket Names for the list of possible values. Server-Only
Spawn([table parameters]) None Resurrects a dead player or spawns a despawned player based on respawn settings in the game (default in-place). An optional table may be provided to override the following parameters:
position (Vector3): Respawn at this position. Defaults to the position of the spawn point selected based on the game's respawn settings, or the player's current position if no spawn point was selected.
rotation (Rotation): Sets the player's rotation after respawning. Defaults to the rotation of the selected spawn point, or the player's current rotation if no spawn point was selected.
scale (Vector3): Sets the player's scale after respawning. Defaults to the Player Scale Multiplier of the selected spawn point, or the player's current scale if no spawn point was selected. Player scale must be uniform. (All three components must be equal.)
spawnKey (string): Only spawn points with the given spawnKey will be considered. If omitted, only spawn points with a blank spawnKey are used.
Server-Only
Despawn() None Despawns the player. While despawned, the player is invisible, has no collision, and cannot move. Use the Spawn() function to respawn the player. Server-Only
Respawn([table parameters]) None This function is deprecated. Please use Player:Spawn() instead. Resurrects a dead Player based on respawn settings in the game (default in-place). An optional table may be provided to override the following parameters:
position (Vector3): Respawn at this position. Defaults to the position of the spawn point selected based on the game's respawn settings, or the player's current position if no spawn point was selected.
rotation (Rotation): Sets the player's rotation after respawning. Defaults to the rotation of the selected spawn point, or the player's current rotation if no spawn point was selected.
scale (Vector3): Sets the player's scale after respawning. Defaults to the Player Scale Multiplier of the selected spawn point, or the player's current scale if no spawn point was selected. Player scale must be uniform. (All three components must be equal.)
spawnKey (string): Only spawn points with the given spawnKey will be considered. If omitted, only spawn points with a blank spawnKey are used.
Server-Only, Deprecated
Respawn(Vector, Rotation) None This function is deprecated. Please use Player:Spawn() instead. For example: player:Spawn({position = newPosition, rotation = newRotation}) Resurrects a dead Player at a specific location and rotation. Server-Only, Deprecated
GetViewWorldPosition() Vector3 Get position of the Player's camera view. None
GetViewWorldRotation() Rotation Get rotation of the Player's camera view. None
GetLookWorldRotation() Rotation Get the rotation for the direction the Player is facing. None
SetLookWorldRotation(Rotation) None Set the rotation for the direction the Player is facing. Client-Only
ClearResources() None Removes all resources from a player. Server-Only
GetResources() table<string, integer> Returns a table containing the names and amounts of the player's resources. None
GetResource(string name) integer Returns the amount of a resource owned by a player. Returns 0 by default. None
SetResource(string name, integer amount) None Sets a specific amount of a resource on a player. Server-Only
AddResource(string name, integer amount) None Adds an amount of a resource to a player. Server-Only
RemoveResource(string name, integer amount) None Subtracts an amount of a resource from a player. Does not go below 0. Server-Only
TransferToGame(string) None Does not work in preview mode or in games played locally. Transfers player to the game specified by the passed-in game ID. Example: The game ID for the URL https://www.coregames.com/games/577d80/core-royale is 577d80/core-royale. This function will raise an error if called from a client script on a player other than the local player. None
TransferToGame(CoreGameInfo) None Does not work in preview mode or in games played locally. Transfers player to the game specified by the passed-in CoreGameInfo. This function will raise an error if called from a client script on a player other than the local player. None
TransferToGame(CoreGameCollectionEntry) None Does not work in preview mode or in games played locally. Transfers player to the game specified by the passed-in CoreGameCollectionEntry. This function will raise an error if called from a client script on a player other than the local player. None
TransferToScene(string sceneName, [table parameters]) None Does not work in preview mode or in games played locally. Transfers player to the scene specified by the passed-in scene name. The specified scene must be a scene within the same game. This function will raise an error if called from a client script on a player other than the local player.
The following optional parameters are supported:
spawnKey (string): Spawns the player at a spawn point with a matching key. If an invalid key is provided, the player will spawn at the origin, (0, 0, 0).
Server-Only
GetAttachedObjects() Array<CoreObject> Returns a table containing CoreObjects attached to this player. None
SetMounted(boolean) None Forces a player in or out of mounted state. Server-Only
GetActiveCamera() Camera Returns whichever camera is currently active for the Player. Client-Only
GetDefaultCamera() Camera Returns the default Camera object the Player is currently using. Client-Only
SetDefaultCamera(Camera, [number lerpTime = 0.0]) None Sets the default Camera object for the Player. Client-Only
GetOverrideCamera() Camera Returns the override Camera object the Player is currently using. Client-Only
SetOverrideCamera(Camera, [number lerpTime = 0.0]) None Sets the override Camera object for the Player. Client-Only
ClearOverrideCamera([number lerpTime = 0.0]) None Clears the override Camera object for the Player (to revert back to the default camera). Client-Only
ActivateFlying() None Activates the Player flying mode. Server-Only
ActivateWalking() None Activate the Player walking mode. Server-Only
IsBindingPressed(string bindingName) boolean This function is deprecated. Please use Input.IsActionHeld() instead, but note that it does not use the same binding names. Returns true if the player is currently pressing the named binding. Possible values of the bindings are listed on the Ability binding page. Note that when called on a client, this function will only work for the local player. Deprecated
HasPerk(NetReference) boolean Returns true if the player has one or more of the specified perk. None
GetPerkCount(NetReference) integer Returns how many of the specified perk the player owns. For non-repeatable perks, returns 1 if the player owns the perk, or 0 if the player does not. None
GetPerkTimeRemaining(NetReference) number Returns the amount of time remaining (in seconds) until a Limited Time Perk expires. Returns 0 if the player does not own the specified perk, or infinity for a permanent or repeatable perk that the player owns. None
AttachToCoreObject(CoreObject) None Attaches the Player to the given CoreObject, treating that object as a parent and disabling player movement. Server-Only
Detach() None If the Player is attached to a parent CoreObject, detaches them and re-enables player movement. Server-Only
GetJoinTransferData() PlayerTransferData Returns data indicating how a player joined the game (via browsing, portal, social invite, etc) and the game ID of their previous game if they joined directly from another game. Join data should be available during the player's entire session. None
GetLeaveTransferData() PlayerTransferData Returns data indicating how a player left the game (via browsing, portal, social invite, etc) and the game ID of their next game if they are directly joining another game. Leave data is not valid until Game.playerLeftEvent has fired for the player. None
SetPrivateNetworkedData(string key, value) PrivateNetworkedDataResultCode Sets the private networked data for this player associated with the key. Value can be any type that could be sent with a networked event. Each key is replicated independently, and this data is only sent to the owning player. Server-Only
GetPrivateNetworkedData(string key) value Returns the private networked data on this player associated with the given key or nil if no data is found. None
GetPrivateNetworkedDataKeys() Array<string> Returns an array of all keys with private data set. None
GetPrivateNetworkedDataSize() integer Returns the number of bytes used by private networked data on this player. Returns 0 if private networked data is not available. None
GrantRewardPoints(int rewardPoints, string activityName) None Adds an amount of Reward Points to a player for completing a certain activity. Server-Only
GetIKAnchors() Array<IKAnchor> Returns an array of all IKAnchor objects activated on this player. None
IsInPartyWith(Player) boolean Returns whether both players are in the same public party. None
GetPartyInfo() PartyInfo If the player is in a party, returns a PartyInfo object with data about that party. None
GetInventories() Array<Inventory> Returns a list of Inventory objects assigned to the player. If the player has no assigned inventories, this list is empty. None
GetInteractableTarget() Trigger If the player is currently focused on an interactable Trigger, returns that Trigger. Returns nil if the player is not currently focused on an interactable Trigger. Client-Only
GetActiveAbility() Ability Returns the Ability that is currently active on the player, or nil if no ability is currently active. Abilities are considered active if they are in CAST, EXECUTE, or RECOVERY phases. Abilities in COOLDOWN or READY phase are not considered active. None

Events

Event Name Return Type Description Tags
damagedEvent Event<Player player, Damage damage> Fired when the Player takes damage. Server-Only
diedEvent Event<Player player, Damage damage> Fired when the Player dies. Server-Only
respawnedEvent Event<Player player> Fired when the Player respawns. This event has been deprecated. Please use spawnedEvent instead. Server-Only, Deprecated
spawnedEvent Event<Player player, PlayerStart playerStart, string spawnKey> Fired when the Player spawns. Indicates the start point at which they spawned and the spawn key used to select the start point. The start point may be nil if a position was specified when spawning the player. Server-Only
bindingPressedEvent Event<Player player, string binding> This event is deprecated. Please use Input.actionPressedEvent instead, but note that it does not use the same binding names. Fired when an action binding is pressed. Second parameter tells you which binding. Possible values of the bindings are listed on the Ability binding page. Deprecated
bindingReleasedEvent Event<Player player, string binding> This event is deprecated. Please use Input.actionReleasedEvent instead, but note that it does not use the same binding names. Fired when an action binding is released. Second parameter tells you which binding. Deprecated
resourceChangedEvent Event<Player player, string resourceType, integer newAmount> Fired when a resource changed, indicating the type of the resource and its new amount. None
perkChangedEvent Event<Player player, NetReference perkReference> Fired when a player's list of owned perks has changed, indicating which perk's amount has changed. Do not expect this event to fire for perks that a player already has when they join a game. Use the HasPerk(NetReference) or GetPerkCount(NetReference) function for any initial logic that needs to be handled when joining. Also, this event may not actively fire when a perk expires, but it may fire for an expired perk as a result of purchasing a different perk. None
movementModeChangedEvent Event<Player player, MovementMode newMovementMode, MovementMode previousMovementMode> Fired when a Player's movement mode changes. The first parameter is the Player being changed. The second parameter is the "new" movement mode. The third parameter is the "previous" movement mode. Possible values for MovementMode are: MovementMode.NONE, MovementMode.WALKING, MovementMode.FALLING, MovementMode.SWIMMING, MovementMode.FLYING. None
emoteStartedEvent Event<Player player, string emoteId> Fired when the Player begins playing an emote. None
emoteStoppedEvent Event<Player player, string emoteId> Fired when the Player stops playing an emote or an emote is interrupted. None
animationEvent Event<Player player, string eventName, string animationName> Some animations have events specified at important points of the animation (for example the impact point in a punch animation). This event is fired with the Player that triggered it, the name of the event at those points, and the name of the animation itself. Events generated from default stances on the player will return "animation_stance" as the animation name. Client-Only
privateNetworkedDataChangedEvent Event<Player player, string key> Fired when the player's private data changes. On the client, only the local player's private data is available. None
collidedEvent Event<Player player, HitResult hitResult> Fired when a player collides with another object. The HitResult parameter describes the collision that occurred. None
interactableFocusedEvent Event<Player player, Trigger trigger> Fired when a player has focused on an interactable Trigger and may interact with it. Client-Only
interactableUnfocusedEvent Event<Player player, Trigger trigger> Fired when a player is no longer focused on a previously focused interactable Trigger. Client-Only

Hooks

Hook Name Return Type Description Tags
movementHook Hook<Player player, table parameters> Hook called when processing a Player's movement. The parameters table contains a Vector3 named "direction", indicating the direction the player will move. Client-Only
damageHook Hook<Player player, Damage damage> Hook called when applying damage from a call to ApplyDamage(). The incoming damage may be modified or prevented by modifying properties on the damage parameter. Server-Only

Additional Info

Learn more about Hooks on the Hook API page.

Examples

Example using:

actionPressedEvent

actionReleasedEvent

maxWalkSpeed

maxSwimSpeed

Normally you can leave the Core engine to handle most of the player input. You don't need to explicitly listen to jump events, to make the player jump, for example. But sometimes it's useful to listen to keypress events directly, when creating more complicated interactions.

In this example, when the player pressed the action for sprinting, it will increase the max walk speed. After the player releases the key, the speed will be reset to the baseSpeed

-- Set the action name to use for sprinting.
-- You can created custom bindings in the Bindings Manager.
local ACTION_NAME = script:GetCustomProperty("ActionName")

local baseSpeed = 640
local sprintingSpeed = 1280

function OnActionPressed(player, action)
    if action == ACTION_NAME then
        player.maxWalkSpeed = sprintingSpeed
    end
end

function OnActionReleased(player, action)
    if action == ACTION_NAME then
        player.maxWalkSpeed = baseSpeed
    end
end

Input.actionPressedEvent:Connect(OnActionPressed)
Input.actionReleasedEvent:Connect(OnActionReleased)

See also: Event.Connect


Example using:

animationEvent

In this example, a client script listens for animation events on the player. When one such occurs, information about the event is printed to the Event Log.

function OnAnimationEvent(player, eventName, animationName)
    print(player.name .. " triggered an animation event:")
    print("Event name = " .. eventName)
    print("Animation name = " .. animationName)
end

Game.GetLocalPlayer().animationEvent:Connect(OnAnimationEvent)

See also: Game.GetLocalPlayer


Example using:

damagedEvent

diedEvent

spawnedEvent

ApplyDamage

Die

Spawn

There are events that fire at most major points for a player during gameplay. This example shows how to receive an event for players being damaged, dying, and spawning, as well as how to make a player automatically respawn after dying.

One important thing to note - player.damagedEvent and player.diedEvent only execute on the server, so if you are writing a script that runs inside of a client context, it will not receive these events.

function OnPlayerDamage(player, damage)
    print("Player " .. player.name .. " just took " .. damage.amount .. " damage!")
end

function OnPlayerDied(player, damage)
    print("Player " .. player.name .. " has been killed!")

    -- Now, revive them after 2 seconds at a specific position and rotation:
    Task.Wait(2)
    local pos = Vector3.New(0, 0, 500)
    local rot = Rotation.New(0, 0, 45)
    player:Spawn({position = pos, rotation = rot})
end

function OnPlayerSpawn(player)
    print("Player " .. player.name .. " is back!")
end

-- Set up listeners:
for _, p in pairs(Game.GetPlayers()) do
    p.damagedEvent:Connect(OnPlayerDamage)
    p.diedEvent:Connect(OnPlayerDied)
    p.spawnedEvent:Connect(OnPlayerSpawn)
end
player:ApplyDamage(Damage.New(25))
Task.Wait(1)
player:ApplyDamage(Damage.New(50))
Task.Wait(1)
-- This will kill the player, because they only have 100 health by default.
player:ApplyDamage(Damage.New(100))
Task.Wait(2.1)
-- We can also kill the player directly, regardless of health
player:Die()

See also: Player.name | Damage.New | Task.Wait | CoreLua.print | Vector3.New | Rotation.New | Event.Connect


Example using:

emoteStartedEvent

emoteStoppedEvent

activeEmote

This example combines player emotes with chat messages. Whenever a player begins or ends an emote (Default 'B' key) the server broadcasts a chat message to all players announcing the change.

Also, whenever a player joins the game, the server counts the number of players using any dance emotes and informs the amount to the new player.

local function OnEmoteStarted(player, emoteId)
    local message = player.name .. " is using " .. emoteId
    Chat.BroadcastMessage(message)
end

local function OnEmoteStopped(player, emoteId)
    local message = player.name .. " stopped using " .. emoteId
    Chat.BroadcastMessage(message)
end

local function CountPlayersDancing()
    local result = 0
    for _,player in ipairs(Game.GetPlayers()) do
        local emote = player.activeEmote
        if emote and string.find(emote, "dance") then
            result = result + 1
        end
    end
    return result
end

local function OnPlayerJoined(player)
    player.emoteStartedEvent:Connect(OnEmoteStarted)
    player.emoteStoppedEvent:Connect(OnEmoteStopped)

    local message = "Welcome to the server " .. player.name ..
    "! There are currently " .. CountPlayersDancing() .. " players dancing."
    Task.Wait(1)
    -- The player may have left during the Task.Wait. Always check if valid
    if Object.IsValid(player) then
        Chat.BroadcastMessage(message, {players = player})
    end
end

Game.playerJoinedEvent:Connect(OnPlayerJoined)

See also: Chat.BroadcastMessage | Game.GetPlayers | Task.Wait | Object.IsValid


Example using:

interactableFocusedEvent

interactableUnfocusedEvent

Similar to the other example, we show a visual indicator on top of interactable object. This time, however, we make use of the player's interactableFocusedEvent and interactableUnfocusedEvent events. This gives us the exact moment the interaction focus begins/ends, which is used to hide/show the VFX.

local INDICATOR_VFX = script:GetCustomProperty("IndicatorVfx"):WaitForObject()
local PLAYER = Game.GetLocalPlayer()

INDICATOR_VFX.visibility = Visibility.FORCE_OFF

function OnInteractableFocused(player, trigger)
    print("Focused: " .. trigger.interactionLabel)

    INDICATOR_VFX:SetWorldPosition(trigger:GetWorldPosition())
    INDICATOR_VFX.visibility = Visibility.INHERIT

    if INDICATOR_VFX.Play then
        -- If the indicator has a Play() function, call it
        INDICATOR_VFX:Play()
    end
end

function OnInteractableUnfocused(player, trigger)
    print("Unfocused: " .. trigger.interactionLabel)

    INDICATOR_VFX.visibility = Visibility.FORCE_OFF
end

PLAYER.interactableFocusedEvent:Connect(OnInteractableFocused)
PLAYER.interactableUnfocusedEvent:Connect(OnInteractableUnfocused)

See also: Trigger.interactionLabel | Vfx.Play | Game.GetLocalPlayer | CoreObject.SetRotation


Example using:

movementModeChangedEvent

Whenever the player changes movement mode, (walking, jumping, swimming, flying), a listener is notified. We can register for that listener if we want to know whenever that happens.

This sample uses that callback to apply falling damage, whenever a player falls too far, and lands on the ground. (Which we test by checking when they transition into the jumping movement mode vs. walking.)

local jumpStartHeight = {}

local MAX_SAFE_FALL_HEIGHT = 500
local FALL_DAMAGE_MULTIPLIER = 1/10

-- Function for when the player changes mode.
function OnMovementModeChanged(player, mode)
    print("change!")
    if mode == MovementMode.FALLING then
        print("jump")
        jumpStartHeight[player] = player:GetWorldPosition().z
    elseif mode == MovementMode.WALKING then
        print("walk")
        if jumpStartHeight[player] ~= nil then
            local fallDistance = jumpStartHeight[player] - player:GetWorldPosition().z
            print("Fell " ..fallDistance)
            if fallDistance > MAX_SAFE_FALL_HEIGHT then
                local damageFromFalling = (fallDistance - MAX_SAFE_FALL_HEIGHT) * FALL_DAMAGE_MULTIPLIER
                print("Took " .. damageFromFalling .. " as fall damage!")
                player:ApplyDamage(Damage.New(damageFromFalling))
            end
        end
        jumpStartHeight[player] = nil
    else
        -- They started swimming or flying or something.
        jumpStartHeight[player] = nil
    end
end

-- Outfit all players with the movementModeChanged listener
function OnPlayerJoined(player)
    player.movementModeChangedEvent:Connect(OnMovementModeChanged)
end

Game.playerJoinedEvent:Connect(OnPlayerJoined)

-- Now we fling the player into the air for testing.
-- When they land they should take ~40 damage.
print("in the air")
player:SetWorldPosition(Vector3.New(0, 0, 1000))
print("done waiting")

See also: Player.GetWorldPosition | Damage.New | Game.playerJoinedEvent | Vector3.z | Event.Connect | CoreLua.print


Example using:

resourceChangedEvent

ClearResources

GetResource

GetResources

SetResource

AddResource

RemoveResource

While scripting, you can assign "resources" to players. These are just integer values, accessed via a string key, that are tied to a player. They are useful for storing values about game-specific resources a player might have, such as coins collected, mana remaining, levels completed, puppies pet, etc.

You can manipulate these values via several methods on the player class, as well as registering for an event when they are changed.

This sample registers a listener to ensure that values are in the 0-100 range, and demonstrates several examples of how to change the values.

local resource1 = "CoinsCollected"
local resource2 = "PuppiesSeen"

-- Make sure that resources never go outside the [0, 100] range:
function OnResourceChanged(player, resourceId, newValue)
    if newValue > 100 then player:SetResource(resourceId, 100) end
    if newValue < 0 then player:SetResource(resourceId, 0) end
end

player.resourceChangedEvent:Connect(OnResourceChanged)

player:SetResource(resource1, 5)
-- Player now has 5 "CoinsCollected"

player:AddResource(resource1, 15)
-- Player now has 20 "CoinsCollected".

player:AddResource(resource1, 500)
-- This should give us 520 "CoinsCollected", but our event listener limits it to 100.
print("Coins collected: " .. player:GetResource(resource1))

player:SetResource(resource2, 2)
-- Player now has 2 "PuppiesSeen", as well as still having 100 "CoinsCollected"

player:RemoveResource(resource1, 10)
-- Player now has 90 "CoinsCollected"

-- We can also get all the resources in one go as a table:
local resourceTable = player:GetResources()
for k, v in pairs(resourceTable) do
    print("Resource ["..k.."]: " .. v)
end

player:ClearResources()
-- All resources have been removed from the player
print("Coins collected: " .. player:GetResource(resource1))
print("Puppies seen: " .. player:GetResource(resource2))

See also: CoreLua.print | Event.Connect


Example using:

GetAttachedObjects

Whether you're building sticky-mines, or costumes, sometimes it is useful to be able to attach a CoreObject directly to a spot on a player.

When attaching an object to a player you need to specify the "socket" you want to attach it to. The list of legal sockets can be found on its own page in the documentation.

local CUBE = script.parent
CUBE.collision = Collision.FORCE_OFF

local function OnPlayerJoined(player)
    -- Attach the cube to the player's head
    CUBE:AttachToPlayer(player, "head")

    -- We can then ask the player for a list of attached CoreObjects:
    print("Attached objects: ")
    for _, v in ipairs(player:GetAttachedObjects()) do
        print(tostring(v.name))
    end
end

Game.playerJoinedEvent:Connect(OnPlayerJoined)

See also: CoreObject.AttachToPlayer


Example using:

damageHook

In this example, players will get armor when they join the game that adds an extra layer of protection to damage sources before it effects the player's health. By using the damageHook for the player, the amount of damage in the Damage object that is passed in can be modified before it is applied to the player.

In this case, the player has an armor resource that the damage is applied to first if the player's armor is greater than 0. Any damage the player takes will notify the source player to show the damage they have done. If the damage is to the armor, then the numbers will be green, otherwise it will be red to indicate damage is to the health.

There are 2 scripts for this example. 1 Server, and 1 Client.

-- Server script

local function ReduceArmor(player, damage)
    local currentArmor = player:GetResource("armor")
    local isArmor = false
    local damageAmount = damage.amount

    -- check the current armor amount for the player who
    -- received the damaged.
    if currentArmor > 0 then

        -- Remove the damage.amount from the armor.
        player:RemoveResource("armor", damage.amount)

        -- Set the damage.amount to 0 so no damage to
        -- the health is took.

        damage.amount = 0
        isArmor = true

        print("Armor for " .. player.name .. " is " .. tostring(player:GetResource("armor")))
    end

    -- Broadcast to the player who is the source of the damage
    -- so the damage numbers will appear on their screen.
    Events.BroadcastToPlayer(damage.sourcePlayer, "ShowDamage", damageAmount, player:GetWorldPosition(), isArmor)
end

-- When the player joins, set their armor resource to 100 and
-- connect up the damageHook event.
local function OnPlayerJoined(player)
    player:SetResource("armor", 100)
    player.damageHook:Connect(ReduceArmor)
end

Game.playerJoinedEvent:Connect(OnPlayerJoined)

-- Client script below

-- Shows the damage numbers to the player. The color
-- of the number depends on if the damage was done to
-- the armor or the health.
local function ShowDamage(damageAmount, position, isArmor)
    UI.ShowFlyUpText(tostring(damageAmount), position, {

        isBig = true,
        color = (isArmor and Color.GREEN) or Color.RED

    })
end

Events.Connect("ShowDamage", ShowDamage)

See also: Hook.Connect | Game.playerJoinedEvent | Damage.amount | player.GetResource | Events.BroadcastToPlayer | UI.ShowFlyUpText


Example using:

movementHook

IsActionHeld

GetViewWorldRotation

In this example, a client script prevents the player from moving normally. It does so connecting to the movementHook and setting the direction to zero. The player will instead move forward only when the Shoot action is pressed (Left mouse button for default bindings).

local PLAYER = Game.GetLocalPlayer()

function OnPlayerMovement(player, params)
    if Input.IsActionHeld(player, "Shoot") then
        local direction = Quaternion.New(PLAYER:GetViewWorldRotation()):GetForwardVector()
        direction.z = 0
        params.direction = direction:GetNormalized()
    else
        params.direction = Vector3.ZERO
    end
end

PLAYER.movementHook:Connect(OnPlayerMovement)

See also: Hook.Connect | Game.GetLocalPlayer | Quaternion.GetForwardVector | Vector3.GetNormalized


Example using:

ActivateFlying

ActivateWalking

You can set different movement modes for the player. ActivateWalking() will give the player normal walking physics. (They fall down, slide down slopes, etc.) ActivateFlying, on the other hand, makes them ignore gravity and fly around freely.

This example allows the player to toggle flying mode by pressing the binding setup.

The binding for flying will need to be networked so the input can be detected on the server.

-- Set the action name to use to toggle flying. A custom binding may needed to need to be
-- added in the Binding Manager window.
local ACTION_NAME = script:GetCustomProperty("ActionName")

function OnActionPressed(player, action)
    if action == ACTION_NAME then
        if player.isFlying then
            player:ActivateWalking()
        else
            player:ActivateFlying()
        end
    end
end

Input.actionPressedEvent:Connect(OnActionPressed)

See also: Input.actionPressedEvent | Event.Connect


Example using:

AddImpulse

GetVelocity

SetVelocity

ResetVelocity

mass

If you want to fling a player using the physics system, it is possible to directly affect their velocity. You can either add a physics impulse to their current velocity, or just set the player's velocity directly. You can also zero out their velocity using Player.ResetVelocity().

Note that when using impulses to apply force to a player, we need to scale it by the player's mass property.

-- Fling the player towards the heavens:
player:SetVelocity(Vector3.UP * 1000)

-- We can read the player's velocity in order to double it! Note that since we're adding
-- a physics impulse directly, we need to scale it by the mass of the player.
player:AddImpulse(player:GetVelocity() * player.mass)

-- Fling the player some more.
player:AddImpulse(Vector3.UP * player.mass * 1000)

Task.Wait(0.5)
-- Reset their velocity to zero.
player:ResetVelocity()

See also: Player.SetWorldPosition | Task.Wait | Vector3.ZERO


Example using:

AttachToCoreObject

Detach

parentCoreObject

In this example, the script is placed as a child of a simple networked cube. The cube is set to move slowly upwards. When a player presses the Shoot binding, they are attached to the cube and follow its movement. Pressing the binding again detaches them from the cube and they fall off.

local CUBE = script.parent

CUBE:MoveContinuous(Vector3.UP * 20)

function OnActionPressed(player, action)
    if action == "Shoot" then
        if player.parentCoreObject then
            -- Detach from cube
            player:Detach()
        else
            -- Attach to cube
            player:AttachToCoreObject(CUBE)
        end
    end
end

Input.actionPressedEvent:Connect(OnActionPressed)

See also: CoreObject.parent | Vector3.UP | Input.actionPressedEvent


Example using:

DisableRagdoll

EnableRagdoll

animationStance

You can enable ragdoll on a player, and make their joints all floppy. This can be useful for various effects, such as indicating when a player has died, or otherwise needs to be limp.

Alternately, you can set the player's animation stance to one of a number of premade animation stances, and the player will move while maintaining that stance. Check out the "Player Animations" page for a complete list.

-- Set the player's limbs to flop around, but leave the main spine
-- intact, so we drag them around like a marionette:
player:EnableRagdoll("lower_spine", .4)
player:EnableRagdoll("right_shoulder", .2)
player:EnableRagdoll("left_shoulder", .6)
player:EnableRagdoll("right_hip", .6)
player:EnableRagdoll("left_hip", .6)
Task.Wait(3)
-- Back to normal!
player:DisableRagdoll()

-- Okay now let's give them a weird stance:
player.animationStance = "unarmed_sit_car_low"
Task.Wait(3)
-- Put it back to normal
player.animationStance = "unarmed_stance"

See also: Game.playerJoinedEvent | Task.Wait


Example using:

GetAbilities

GetEquipment

Lots of things can end up attached to a player. CoreObject objects, stuck to sockets. Ability and Equipment objects granting them new powers. Etc.

It's possible to query the Player object to find out exactly what is attached to a given player.

local propBasicAssaultRifle = script:GetCustomProperty("BasicAssaultRifle")
rifle = World.SpawnAsset(propBasicAssaultRifle)
rifle:Equip(player)

for _, obj in ipairs(player:GetAbilities()) do
    print("Ability: " .. obj.name)
end
for k,v in pairs(player:GetAbilities()) do
    print(v.name)
end

for _, obj in ipairs(player:GetEquipment()) do
    print("Equipment: " .. obj.name)
end

for _, obj in ipairs(player:GetAttachedObjects()) do
    print("Attached object: " .. obj.name)
end

See also: Player.GetAttachedObjects | CoreObject.GetCustomProperty | World.SpawnAsset | Equipment.Equip | Ability.name | CoreLua.print


Example using:

GetActiveAbility

In this example we have an ability that automatically activates as soon as it can. We could achieve that by calling :Activate() each frame, without verifying anything, however that would cause this ability to interrupt other abilities. By using Player.GetActiveAbility() we can guarantee this ability only activates when there are no others playing.

local ABILITY = script:GetCustomProperty("Ability"):WaitForObject()

function Tick()
    local activeAbility = ABILITY.owner:GetActiveAbility()
    if activeAbility == nil and ABILITY:GetCurrentPhase() == AbilityPhase.READY then
        ABILITY:Activate()
    end
end

See also: Ability.Activate | CoreObject.GetCustomProperty | CoreObjectReference.WaitForObject


Example using:

GetActiveCamera

GetDefaultCamera

SetDefaultCamera

GetOverrideCamera

SetOverrideCamera

ClearOverrideCamera

It's possible to change a player's view by modifying or swapping their camera. This is client side only, and won't have any effect if done from a server context.

local propTestCamera = script:GetCustomProperty("TestCamera")

-- We can set a default camera for a player, and then their viewport
-- is seen through that camera.
local player = Game.GetLocalPlayer()
local defaultCamera = World.SpawnAsset(propTestCamera,
        { position = Vector3.New(0, -1000, 1000) })
defaultCamera:LookAtContinuous(player)

-- Wait 1 frame to make sure the default camera is initialized for the client.
Task.Wait()

print(player:GetDefaultCamera():GetWorldPosition()) -- 0, -1000, 1000
player:SetDefaultCamera(defaultCamera, 1)
Task.Wait(2)

-- Players also have an "override camera", which has higher priority
-- than the default camera. It's usually used for moving the camera
-- somewhere briefly, before reverting to the default camera.
local overrideCamera = World.SpawnAsset(propTestCamera,
        { position = Vector3.New(0, 1000, 1000) })
overrideCamera:LookAtContinuous(player)
player:SetOverrideCamera(overrideCamera, 1)
print(player:GetOverrideCamera():GetWorldPosition()) -- 0, 1000, 1000
Task.Wait(2)
player:ClearOverrideCamera()
Task.Wait()

See also: CoreObject.GetCustomProperty | Game.GetLocalPlayer | World.SpawnAsset | Vector3.New | Task.Wait | CoreLua.print


Example using:

GetInteractableTarget

In this example, a visual indicator appears on top of any object that has an interactable trigger. For example, a weapon that can be picked up. The indicator spins around its Z axis. This is a client script.

local INDICATOR_VFX = script:GetCustomProperty("IndicatorVfx"):WaitForObject()
local PLAYER = Game.GetLocalPlayer()

function Tick()
    local trigger = PLAYER:GetInteractableTarget()
    if trigger then
        INDICATOR_VFX:SetWorldPosition(trigger:GetWorldPosition())
        INDICATOR_VFX.visibility = Visibility.INHERIT

        local rot = INDICATOR_VFX:GetRotation()
        rot.z = time() * 360
        INDICATOR_VFX:SetRotation(rot)
    else
        INDICATOR_VFX.visibility = Visibility.FORCE_OFF
    end
end

See also: Game.GetLocalPlayer | CoreObject.SetRotation


Example using:

GetInventories

In this example, we periodically check how many inventories each player has and print the result to the Event Log.

function Tick()
    for _,player in ipairs(Game.GetPlayers()) do
        local inventories = player:GetInventories()
        local totalItems = 0
        for _,inventory in ipairs(inventories) do
            totalItems = totalItems + ComputeItemCount(inventory)
        end
        print(player.name.." has "..totalItems.." items across "..#inventories .." inventories.")
    end
    Task.Wait(3)
end

function ComputeItemCount(inventory)
    if inventory.occupiedSlotCount == 0 then return 0 end
    local total = 0
    for i = 1, inventory.occupiedSlotCount do
        local item = inventory:GetItem(i)
        total = total + item.count
    end
    return total
end

See also: Inventory.occupiedSlotCount | InventoryItem.count | Player.name | Game.GetPlayers


Example using:

GetJoinTransferData

In this example, we imagine a project with two separate scenes and players can transfer between them. When a player transfers from the first scene to the second one, we use the optional spawnKey parameter to send team informmaton that can be read from the transfer data when the player has joined the game. Based on the spawn key information the correct weapon template will be spawned for the player.

-- Server Script (Scene 1)
player:TransferToScene("YourSceneName", {

    spawnKey = "Team2" -- Set spawn key to Team2 for this example

})

-- Server Script (Scene 2)
local TEAM_1_WEAPON = script:GetCustomProperty("Team1Weapon")
local TEAM_2_WEAPON = script:GetCustomProperty("Team2Weapon")

local function OnPlayerJoined(player)
    local transferData = player:GetJoinTransferData()
    local weaponTemplate = TEAM_1_WEAPON

    if transferData.spawnKey == "Team2" then
        weaponTemplate = TEAM_2_WEAPON
    end

    local weapon = World.SpawnAsset(weaponTemplate)

    weapon:Equip(player)
end

Game.playerJoinedEvent:Connect(OnPlayerJoined)

See also: CoreObject.GetCustomProperty | World.SpawnAsset | Event.Connect | Player.TransferToScene | Game.playerJoinedEvent | Weapon.Equip | PlayerTransferData.spawnKey


Example using:

GetJoinTransferData

GetLeaveTransferData

In this example, transfer data is printed to the server log each time a player joins or leaves the game. While this works in preview mode, there will never be a gameId in that case, and the reason for the transfer will always be BROWSE. Therefore, this example works best when the game is published.

To see the server logs of a published game, select the Game Settings object in the hierarchy and enable "Play Mode Profiling". When playing the published game press F4 to see the profiler and access the logs. You may need a second player joining/leaving to observe the logs while testing the various different reasons.

-- Converts the enum reason into a string, to make the log more readable
function ToStringTransferReason(reason)
    -- Default reason, or player has opted out from sharing this info
    if reason == PlayerTransferReason.UNKNOWN then return "UNKNOWN" end

    -- If they leave to edit their character/collection
    if reason == PlayerTransferReason.CHARACTER then return "CHARACTER" end

    -- If they leave by pressing the "Create" tab
    if reason == PlayerTransferReason.CREATE then return "CREATE" end

    -- If they leave by pressing the "Shop" tab
    if reason == PlayerTransferReason.SHOP then return "SHOP" end

    -- If they join/leave by browsing games or from a URL
    if reason == PlayerTransferReason.BROWSE then return "BROWSE" end

    -- If they join/leave by joining a game their friend is playing
    if reason == PlayerTransferReason.SOCIAL then return "SOCIAL" end

    -- If they join/leave when a game uses player:TransferToGame()
    if reason == PlayerTransferReason.PORTAL then return "PORTAL" end

    -- If they leave from being inactive for longer than the AFK limit
    if reason == PlayerTransferReason.AFK then return "AFK" end

    -- If they close Core or log out
    if reason == PlayerTransferReason.EXIT then return "EXIT" end

    -- Fallback, future-proof
    return "???" .. tostring(reason)
end

-- Given a game ID, retrieves the game's name and author
function FetchGameNameAndAuthor(gameId)
    if gameId then
        -- This yields the thread while the data is retrieved
        local gameInfo = CorePlatform.GetGameInfo(gameId)
        if gameInfo then
            return gameInfo.name .. ", by " .. gameInfo.ownerName
        end
    end
    return ""
end

function OnPlayerJoined(player)
    -- CorePlatform.GetGameInfo creates a delay while the data is being retrieved, during
    -- which time the player object may no longer be valid, so we cache the name first.
    local playerName = player.name
    local transferData = player:GetJoinTransferData()
    local gameId = transferData.gameId
    local reason = ToStringTransferReason(transferData.reason)
    local gameBio = FetchGameNameAndAuthor(gameId)
    print(
    "\n Player joined = " .. playerName ..
    "\n from game = " .. tostring(gameId) .. ":" .. gameBio ..
    "\n reason = " .. reason)
end

function OnPlayerLeft(player)
    -- CorePlatform.GetGameInfo creates a delay while the data is being retrieved, during
    -- which time the player object may no longer be valid, so we cache the name first.
    local playerName = player.name
    local transferData = player:GetLeaveTransferData()
    local gameId = transferData.gameId
    local reason = ToStringTransferReason(transferData.reason)
    local gameBio = FetchGameNameAndAuthor(gameId)
    print(
    "\n Player left = " .. playerName ..
    "\n to game = " .. tostring(gameId) .. ":" .. gameBio ..
    "\n reason = " .. reason)
end

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

See also: PlayerTransferData.gameId | PlayerTransferReason | Player.TransferToGame | Game.TransferAllPlayersToGame | CoreGameInfo.name


Example using:

GetPartyInfo

isInParty

isPartyLeader

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: PartyInfo.GetMemberIds | Game.TransferPlayersToGame | CorePlatform.GetGameCollection | Trigger.beginOverlapEvent | CoreObjectReference.WaitForObject | Other.IsA


Example using:

GetViewWorldPosition

GetViewWorldRotation

GetLookWorldRotation

SetLookWorldRotation

The direction and rotation that the player is looking can be both read and set through Lua scripts. Note that this will only work on scripts executing inside of a client context.

local player = Game.GetLocalPlayer()
-- Get the position and direction of the player's camera:
print("The player's view camera is at " .. tostring(player:GetViewWorldPosition()))
print("Its rotation is " .. tostring(player:GetViewWorldRotation()))

-- You can also directly set which direction they are looking.
-- This code snippet will force them to look 90 degrees to the right.
player:SetLookWorldRotation(player:GetLookWorldRotation() + Rotation.New(0, 0, 90))

See also: Game.GetLocalPlayer | CoreLua.print | Rotation.New


Example using:

GetWorldTransform

SetWorldTransform

GetWorldPosition

SetWorldPosition

GetWorldRotation

SetWorldRotation

It is possible to read and change the position of the player. You can either change the position or rotation directly, or change the entire transformation all at once.

-- Store off the transform of the player:
player:SetWorldTransform(Transform.IDENTITY)
local originalTransform = player:GetWorldTransform()

-- Move the player 1000 units in the air:
player:SetWorldPosition(player:GetWorldPosition() + Vector3.UP * 1000)

-- Look 90 degrees to the right
player:SetWorldRotation(player:GetWorldRotation() + Rotation.New(0, 0, 90))

-- Return the player to their original position and rotation:
player:SetWorldTransform(originalTransform)

See also: Rotation.New | Vector3.UP


Example using:

GrantRewardPoints

In this example, a player receives a daily reward of 100 points (RP) when they join the game. The reward name can be anything, so we use "Daily" here, to identify it. Lua's os.date() system is used in conjunction with Storage, to figure out if this is the first time the player has joined today.

local REWARD_AMOUNT = 100
local REWARD_NAME = "Daily"

function IsFirstJoinToday(player)
    local today = os.date("*t")
    local day = today.day
    local month = today.month

    print("Day = " .. day)
    print("Month = " .. month)

    local data = Storage.GetPlayerData(player)
    if day ~= data.lastJoinDay
    or month ~= data.lastJoinMonth then
        data.lastJoinDay = day
        data.lastJoinMonth = month
        Storage.SetPlayerData(player, data)
        return true
    end
    return false
end

function OnPlayerJoined(player)
    if IsFirstJoinToday(player) then
        player:GrantRewardPoints(REWARD_AMOUNT, REWARD_NAME)
        print("Awarded")
    else
        print("Not awarded")
    end
end

Game.playerJoinedEvent:Connect(OnPlayerJoined)

See also: Storage.GetPlayerData | Game.playerJoinedEvent


Example using:

HasPerk

In this example, limited time perks that players have purchased could still have active benefits (that is double xp) when the perk has expired while the player is still on the server. This could allow players to get extended perk benefits until they leave, or the server is closed.

To solve this issue, a task can be spawned that checks all players on the server periodically if they have the limited time perk. For example, you might be using SetResource to flag players having a Gold VIP Pass. If the limited time perk has expired, then the flag can be set to 0, which would end the benefits for the player until they repurchase the perk.

-- Server script

-- The limited time perk (net reference) to check.
local LIMITED_TIME_PERK = script:GetCustomProperty("perk")

-- Spawn the task when the server starts
local perkCheckTask = Task.Spawn(function()

    -- Loop through all the players on the server.
    for index, player in ipairs(Game.GetPlayers()) do

        -- If the player does not have the perk, reset their vip pass.
        if not player:HasPerk(LIMITED_TIME_PERK) then

            -- Your code would go here to handle resetting perk benefits.
            player:SetResource("goldvippass", 0)
        end
    end
end)

perkCheckTask.repeatCount = -1

-- The interval doesn't need to be fast
perkCheckTask.repeatInterval = (60 * 5)

See also: CoreObject.GetCustomProperty | Task.Spawn | Game.GetPlayers | Player.SetResource


Example using:

SetPrivateNetworkedData

GetPrivateNetworkedData

GetPrivateNetworkedDataKeys

privateNetworkedDataChangedEvent

In this example, a player's inventory data is transferred from server to client. The server first accesses permanent storage to see if the player has previously played the game. If not, their inventory is initialized with starting items. Then, the server uses the private networked data API to transfer this information to the client script. Client scripts cannot access storage directly, so they depend on this transfer in order to display to the user interface what's contained in the inventory. Furthermore, because the transfer is private, other players don't incur networking costs. Plus, knowing other players' inventories is not important for the gameplay in this case.

-- BEGIN REGION: Server script
function InitInventory(player, data)
    if not data.inventory then
        print(player.name .. " is a new player. Give them starting inventory.")
        data.inventory = {
            ["sword"] = 1,
            ["shield"] = 1,
            ["rupies"] = 15,
        }
    else
        print(player.name .. " already has inventory from a previous play session.")
    end
    player.serverUserData.inventory = data.inventory
end

function OnPlayerJoined(player)
    local data = Storage.GetPlayerData(player)
    InitInventory(player, data)

    -- Transfer storage to the client
    for key,value in pairs(data) do
        local resultCode = player:SetPrivateNetworkedData(key, value)

        if resultCode == PrivateNetworkedDataResultCode.FAILURE then
            warn("Setting private data " .. key .. " for player " ..
                player.name .. " failed.")

        elseif resultCode == PrivateNetworkedDataResultCode.EXCEEDED_SIZE_LIMIT then
            warn("Setting private data " .. key .. " for player " ..
                player.name .. " exceeded the limit.")
        end
    end
end

function OnPlayerLeft(player)
    local data = Storage.GetPlayerData(player)
    data.inventory = player.serverUserData.inventory
    Storage.SetPlayerData(player, data)
end

Game.playerJoinedEvent:Connect(OnPlayerJoined)
Game.playerLeftEvent:Connect(OnPlayerLeft)
-- END REGION: Server script

-- BEGIN REGION: Client script
local PLAYER = Game.GetLocalPlayer()

function UpdateFromNetworkedData(key)
    local data = PLAYER:GetPrivateNetworkedData(key)
    -- This would depend on your type of data and game system
    -- For example: An inventory of items
    if key == "inventory" then
        for itemId,count in pairs(data) do
            print(PLAYER.name .. " has " .. count .. " copies of " .. itemId)
        end
        PLAYER.clientUserData.inventory = data
    end
end

-- React to changes in the data, or receive the initial replication in case
-- the client script loaded before the networked data had replicated
function OnPrivateNetworkedDataChanged(player, key)
    UpdateFromNetworkedData(key)
end

PLAYER.privateNetworkedDataChangedEvent:Connect(OnPrivateNetworkedDataChanged)

-- In case the client script loaded after the networked data has replicated
for i,key in ipairs(PLAYER:GetPrivateNetworkedDataKeys()) do
    UpdateFromNetworkedData(key)
end
-- END REGION: Client script

See also: Storage.GetPlayerData | Game.playerJoinedEvent | Player.clientUserData


Example using:

SetWorldScale

GetWorldScale

You can scale the size of the player. This sample causes all players to slowly grow until they get too big, and then reset.

Task.Spawn(function()
    while true do
        for _, player in pairs(Game.GetPlayers()) do
            local currentScale = player:GetWorldScale()
            local newScale = currentScale * 1.01
            if newScale.x > 5 then newScale = Vector3.New(1.0) end

            player:SetWorldScale(newScale)
        end
        Task.Wait()
    end
end)

See also: Task.Spawn | Game.GetPlayers | Vector3.New


Example using:

TransferToGame

Sends a player to another game. The game ID can be obtained from the Core website, for example to transfer a player to Core Royale, we navigate to that game's page at https://www.coregames.com/games/577d80/core-royale and copy the last two parts of the URL 577d80/core-royale as the game ID.

local trigger = script.parent

function OnBeginOverlap(theTrigger, player)
  -- The object's type must be checked because CoreObjects also overlap triggers
    if player and player:IsA("Player") then
        player:TransferToGame("e39f3e/core-world")
    end
end

trigger.beginOverlapEvent:Connect(OnBeginOverlap)

See also: CoreObject.parent | Object.IsA | Trigger.beginOverlapEvent | Event.Connect


Example using:

TransferToScene

This example shows how to transfer a player to a scene called Tutorial when the player overlaps the trigger. By setting the optional spawn parameter, the player will spawn at a specific location when loading into the scene.

It's important that the scene name used, matches exactly the name for the scene you want to transfer the player too.

local PORTAL_TRIGGER = script:GetCustomProperty("PortalTrigger"):WaitForObject()

-- Name of the scene to transfer the player too.
local sceneName = "Tutorial"

-- Function will be called when the player overlaps the trigger.
local function OnTriggerOverlap(trigger, obj)

    -- Check the object overlapping the trigger is a Player.
    if obj:IsA("Player") then

        -- Transfer the player to the scene, and set the spawn point.
        obj:TransferToScene(sceneName, { spawnKey = "TutorialStart" })
    end
end

PORTAL_TRIGGER.beginOverlapEvent:Connect(OnTriggerOverlap)

See also: Game.TransferAllPlayersToScene | Other.IsA | Trigger.beginOverlapEvent


Example using:

isVisible

You can make a player visible or invisible by setting the isVisible property, as well as check on their current visibility status. This sample gives the player the ability to turn invisible by pressing a key.

-- Set the action name to use for going invisible. A custom binding may need to need to be
-- added in the Binding Manager window.
local ACTION_NAME = script:GetCustomProperty("ActionName")

function OnActionPressed(player, action)
    if action == ACTION_NAME then
        player.isVisible = false
    end
end

function OnActionReleased(player, action)
    if action == ACTION_NAME then
        player.isVisible = true
    end
end

Input.actionPressedEvent:Connect(OnActionPressed)
Input.actionReleasedEvent:Connect(OnActionReleased)

See also: Input.actionPressedEvent | Event.Connect | CoreObject.GetCustomProperty


Example using:

collidedEvent

Each time a player bumps into another object they fire a collidedEvent. This example works on both server and client scripts. It shows how to connect to the event and prints the names of the objects into the Event Log.

local function OnPlayerCollided(player, hitResult)
    print(player.name .. " collided with " .. hitResult.other.name)
end

local function OnPlayerJoined(player)
    player.collidedEvent:Connect(OnPlayerCollided)
end

Game.playerJoinedEvent:Connect(OnPlayerJoined)

See also: HitResult.other | Game.playerJoinedEvent | Event.Connect


Example using:

currentFacingMode

desiredFacingMode

There are several modes the game can use to decide which direction the player's avatar is facing, based on the camera look direction.

-- This will make the player turn to face whatever direction they are moving.
player.desiredFacingMode = FacingMode.FACE_MOVEMENT

-- This will make the player turn to face whatever direction they are aiming.
player.desiredFacingMode = FacingMode.FACE_AIM_ALWAYS

-- This will make the player turn to face whatever direction they
-- are moving or shooting.
player.desiredFacingMode = FacingMode.FACE_AIM_WHEN_ACTIVE

--[[#description
Note that this is the _desired_ facing mode. The actual facing mode is not
always guaranteed to be this, as certain player states can override this.
(When the player is swimming, for example.

You can check the actual current facing mode using the `currentFacingMode`
property.]]

if (player.currentFacingMode == FacingMode.FACE_AIM_ALWAYS) then
    print("Player's facing mode is FacingMode.FACE_AIM_ALWAYS!")
end

See also: Game.playerJoinedEvent | CoreLua.print


Example using:

hitPoints

maxHitPoints

kills

deaths

You can get various vital statistics off of the player object, such as hit points, max hit points, kills, and deaths. This sample shows how to read that data and populate a leaderboard. (The leaderboard is printed out to the event log in this sample, but it would be trivial to feed it into some kind of onscreen UI.)

-- Here's a function to print out various useful information about the player's current status
-- and score to the event log.
function PrintPlayerStats(player)
    print("[" .. player.name .. "]: Health: (".. player.hitPoints .. "/" .. player.maxHitPoints
            .. ") Kills: " .. player.kills
            .. "  Deaths: " .. player.deaths)
end

local playerList = Game.GetPlayers()
table.sort(playerList, function(a, b) return a.kills > b.kills end)
for i, p in ipairs(playerList) do
    PrintPlayerStats(p)
end

See also: Player.name | Game.GetPlayers | CoreLua.print


Example using:

isAccelerating

isCrouching

isFlying

isGrounded

isJumping

isMounted

isSwimming

isWalking

isDead

You can get a lot of useful information about the player's current movement, via a series of read-only boolean properties on the Player object.

-- Here's a function to print out various useful information about the player's current status
-- to the event log.
function CheckPlayerStatus(player)
    print("The player is ...")
    -- isAccelerating is true if the player is accelerating due to input.
    -- IMPORTANT NOTE: isAccelerating only cares about input. It won't turn true if they
    -- are falling, or otherwise accelerating from something other than player input.
    if player.isAccelerating then print("  - moving!") end
    if player.isCrouching    then print("  - crouched!") end
    if player.isFlying       then print("  - flying!") end
    if player.isGrounded     then print("  - touching the ground!") end
    if player.isJumping      then print("  - in mid air!") end
    if player.isMounted      then print("  - riding their mount!") end
    if player.isSwimming     then print("  - underwater!") end
    if player.isWalking      then print("  - moving via walking!") end
    if player.isDead         then print("  - deceased!") end
end

-- For the next 10 seconds, report on a player's status flags!
for i = 0, 10 do
    players = Game.GetPlayers()
    if #players > 0 then
        CheckPlayerStatus(players[1])
    end
    Task.Wait(1)
end

See also: Game.GetPlayers | CoreLua.print | Task.Wait


Example using:

isCollidable

In this example, a trigger makes the player fall through the ground when they step on it. After a short wait period, the player's collision is resumed, so they may interact with whatever else is below the ground.

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

local function OnBeginOverlap(_,player)
    if player:IsA("Player") then
        player.isCollidable = false
        Task.Wait(1.5)
        player.isCollidable = true
    end
end

TRIGGER.beginOverlapEvent:Connect(OnBeginOverlap)

See also: Trigger.beginOverlapEvent | CoreObject.GetCustomProperty | Task.Wait


Example using:

isInParty

isPartyLeader

IsInPartyWith

This example will teleport any players to their team leader if the leader is connected.

function OnPlayerJoined(player)
    -- If the player is not in a party, stop here
    if not player.isInParty then
        return
    end

    local players = Game.GetPlayers()
    -- Go through each player
    for _, p in ipairs(players) do
        -- If the other player is the leader
        if p ~= player and p:IsInPartyWith(player) and p.isPartyLeader then
            -- Teleport the player to the leader
            player:SetWorldPosition(p:GetWorldPosition())
            return
        end
    end
end

Game.playerJoinedEvent:Connect(OnPlayerJoined)

See also: Game.playerJoinedEvent | Player:IsInPartyWith


Example using:

isMovementEnabled

animationStance

serverUserData

There are different approaches to stunning a player. In this example we disable player movement with isMovementEnabled. We keep count of the number of active stuns, in case more than one stun overlap in duration we don't want the player to exit the stun when the duration of the first one completes.

local STUN_DURATION = 1.5

function ApplyStunToPlayer(player)
    player.isMovementEnabled = false
    player.animationStance = "unarmed_stun_dizzy"

    -- Initialize stun count if needed
    if not player.serverUserData.stunCount then
        player.serverUserData.stunCount = 0
    end
    -- Keep track of how many times stun has been called, in case multiple stuns overlap in time
    player.serverUserData.stunCount = player.serverUserData.stunCount + 1

    -- Duration of the stun effect
    Task.Wait(STUN_DURATION)

    -- Stun effect has passed. Decrease the counter
    player.serverUserData.stunCount = player.serverUserData.stunCount - 1

    -- If there are no more stuns active, cleanup
    if player.serverUserData.stunCount <= 0 then
        player.isMovementEnabled = true

        -- Put the animation back to normal
        player.animationStance = "unarmed_stance"
    end
end

See also: Task.Wait


Example using:

isVisibleToSelf

It's possible to hide the player's model from the player controlling it. This can be especially useful for first-person games. Note that this can only be set by scripts running in the client context.

-- The player can no longer see their own model. Other players' ability
-- to see this player is unaffected.
player.isVisibleToSelf = false

See also: Game.GetLocalPlayer


Example using:

lookSensitivity

You can also make the player's input more or less sensitive, when aiming. This can be useful for aiming down sights, etc.

-- This will double the sensitivity:
player.lookSensitivity = 5

See also: Game.GetLocalPlayer


Example using:

maxAcceleration

brakingDecelerationFalling

brakingDecelerationWalking

groundFriction

brakingFrictionFactor

Through scripts, you can control the player's ability to accelerate their character.

-- The player accelerates more slowly.
player.maxAcceleration = 600

-- The player tends to fall straight down unless they specifically press a direction in mid-air now!
player.brakingDecelerationFalling = 1800

-- The player takes longer to come to rest while walking.
player.brakingDecelerationWalking = 200

-- Also they slide more!
player.groundFriction = 2

-- And more sliding - they have less grip on the ground when decelerating.
player.brakingFrictionFactor = 0.2

See also: Game.playerJoinedEvent


Example using:

movementControlMode

lookControlMode

defaultRotationRate

currentRotationRate

Player motion and facing can be set to several modes, depending on the gameplay needed.

-- The player's movement input is ignored. Player cannot move.
player.movementControlMode = MovementControlMode.NONE

-- Movement follows the player's current view direction. This is
-- the direction the camera is pointing.
player.movementControlMode = MovementControlMode.VIEW_RELATIVE

-- Movement follows the player's current look direction.
-- This is the direction the player's head is facing.
player.movementControlMode = MovementControlMode.LOOK_RELATIVE

-- Movement follows the player's current facing direction
-- This is the direction that the player's torso is facing.
player.movementControlMode = MovementControlMode.FACING_RELATIVE

player.defaultRotationRate = 200

--[[#description
    You can also change how the player's look input is processed:
]]
-- Player look input is ignored. The player cannot move their view.
player.lookControlMode = LookControlMode.NONE

-- The player controls the look direction. This is the default mode.
player.lookControlMode = LookControlMode.RELATIVE

-- The player always turns to face whatever the cursor is over, in the world.
-- This works best with a third person camera.
player.lookControlMode = LookControlMode.LOOK_AT_CURSOR

See also: Game.playerJoinedEvent


Example using:

name

id

team

There is a lot of useful information you can get from the player object. Players have a name property, which is the text display name for the player. Players can set their own names though, so there is no guarantee that names will be unique.

Players do, however, have a unique ID assigned to them. (Accessed via the id property.) It is guaranteed to be distinct from other players, and it is stable across sessions, so it won't change if they log out and log back in again.

This sample grabs the list of all current players, and prints out their name, ID, and what team they are on.

local players = Game.GetPlayers()
print("---There are currently " .. tostring(#players) .. " Player(s):")
for _, p in pairs(players) do
    print("Player [" .. p.name .. "]:")
    print("  - id:   " .. p.id)
    print("  - team: " .. p.team)
    print()
end

See also: Game.GetPlayers | CoreLua.print


Example using:

occupiedVehicle

In this example, we can imagine a racing game where various start points are defined for the players. When a new round starts we teleport all players who have a vehicle to the starting points, so they can begin a new race. The start point objects are all children of a common group/folder that is set as a custom property. The objects used for start points can be anything, such as an empty group. For this type of invisible "level design object", sometimes creators use a server-context with a static mesh inside, so you can see the points during edit time, but they won't appear or collide for clients.

local START_POINTS_PARENT = script:GetCustomProperty("StartPoints"):WaitForObject()
local START_POINTS = START_POINTS_PARENT:GetChildren()

function OnRoundStart()
    for i,player in ipairs(Game.GetPlayers()) do
        local vehicle = player.occupiedVehicle
        if vehicle then
            -- Teleport them to the start points
            local startPoint = START_POINTS[i]
            if startPoint then
                local pos = startPoint:GetWorldPosition()
                local rot = startPoint:GetWorldRotation()
                vehicle:SetWorldPosition(pos)
                vehicle:SetWorldRotation(rot)
            else
                warn("Insufficient start points for all players")
            end
            -- Stop their movement
            vehicle:SetVelocity(Vector3.ZERO)
            vehicle:SetAngularVelocity(Vector3.ZERO)
        end
    end
end

Game.roundStartEvent:Connect(OnRoundStart)

See also: CoreObject.SetVelocity | CoreObjectReference.WaitForObject | Game.GetPlayers | Vector3.ZERO


Example using:

shouldDismountWhenDamaged

SetMounted

canMount

The player can mount or dismount. We can also force the player to mount or dismount via the Player:SetMounted() function. Also, if Player.shouldDismountWhenDamaged is set, they will automatically dismount whenever they take damage.

This sample demonstrates how to force the player to be mounted, and how to set them to dismount when hit.

player.shouldDismountWhenDamaged = true
player:SetMounted(true)
-- Player is now mounted!

-- If they take damage, they should dismount!

player:ApplyDamage(Damage.New(1))

-- We can also disable the player's ability to mount or dismount.
-- Note that this will NOT prevent us from calling SetMounted() -
-- this only affects the player's controls.
player.canMount = false

See also: Player.ApplyDamage | Damage.New | Task.Wait


Example using:

spreadModifier

currentSpread

Players shooting weapons have a spread modifier applied to their accuracy. This can be used to simulate things like loss of aim after jumping, or other activities.

-- Whenever the player lands after a jump, they get more spread
-- on their shots for a second.
local jumpEndListener = player.movementModeChangedEvent:Connect(
    function(player, movementMode)
        if movementMode == MovementMode.WALKING then
            print("Worse aim!")
            player.spreadModifier = 2
            Task.Wait(1)
            print("better aim!")
            player.spreadModifier = 1
        end
    end)
    --[[#description
        You can also check the player's current (total) spread,
        although this only works from the client context.
    ]]
    print(player.currentSpread)

See also: Player.movementModeChangedEvent | Task.Wait | Event.Connect | CoreLua.print


Example using:

stepHeight

walkableFloorAngle

maxJumpCount

jumpVelocity

gravityScale

buoyancy

isCrouchEnabled

Most of the aspects of a player's movement can be controlled at runtime via scripting.

-- Player can now step over 100cm ledges!
player.stepHeight = 100

-- And walk up 60-degree inclines!
player.walkableFloorAngle = 60

-- Player can now double-jump!
player.maxJumpCount = 2

-- And jump twice as high!
player.jumpVelocity = 1800

-- But gravity is twice as strong!
player.gravityScale = 3.8

-- But they are twice as buoyant in water!
player.buoyancy = 2

-- Also the player cannot crouch.
player.isCrouchEnabled = false

See also: Game.playerJoinedEvent


Example using:

touchForceFactor

When the player runs into physics objects, they exert force. You can affect how much force with the touchForceFactor property.

-- Set the player to push five times as hard!
player.touchForceFactor = 5

See also: CoreObject.SetVelocity | StaticMesh.isSimulatingDebrisPhysics


Example using:

perkChangedEvent

GetPerkCount

Perks are a system to create in-game purchases that allow players to support game creators and enable exclusive content.

Learn more about Perks here.

Repeatable Perks - This type of Perk can be purchased any number of times by players. In this example, we implement the sale of in game currency through multiple bundles and track the purchases using storage and resources. This script will track each Perk bundle to grant users the currency/resource.

local RESOURCE_KEY = "Gem" -- Example currency, can be any resource

-- Perks, of type Net Reference, assigned by dragging from the Perks Manager window
local PERK_1 = script:GetCustomProperty("Perk1")
local PERK_2 = script:GetCustomProperty("Perk2")
local PERK_3 = script:GetCustomProperty("Perk3")

-- Reward amounts per bundle, of type Integer
local PERK_1_REWARD = script:GetCustomProperty("Perk1Reward")
local PERK_2_REWARD = script:GetCustomProperty("Perk2Reward")
local PERK_3_REWARD = script:GetCustomProperty("Perk3Reward")

-- Internal bundles data with bundle storage id and custom rewards per Perk.
-- These rewards can be changed after the game goes live.
local bundles = {}
table.insert(bundles, {perk = PERK_1, storageId = "GemBundle1", reward = PERK_1_REWARD})
table.insert(bundles, {perk = PERK_2, storageId = "GemBundle2", reward = PERK_2_REWARD})
table.insert(bundles, {perk = PERK_3, storageId = "GemBundle3", reward = PERK_3_REWARD})

-- Check if each storage bundle purchase count is different from Perk purchase count.
-- If yes, then grant currency as reward to the player.
function CheckPerkCountWithStorage(player)
    local data = Storage.GetPlayerData(player)

    for _, bundle in ipairs(bundles) do
        local perkCount = player:GetPerkCount(bundle.perk)
        local storageCount = data[RESOURCE_KEY][bundle.storageId]

        if perkCount ~= storageCount then
            data[RESOURCE_KEY][bundle.storageId] = perkCount
            Storage.SetPlayerData(player, data)

            if perkCount > storageCount then
                local resourceAmount = bundle.reward * (perkCount - storageCount)
                player:AddResource(RESOURCE_KEY, resourceAmount)
            end
        end
    end
end

-- Check and see if storage purchase value is different from Perk purchase count
function UpdateStorageBalance(player)
    local data = Storage.GetPlayerData(player)
    data[RESOURCE_KEY].amount = player:GetResource(RESOURCE_KEY)
    Storage.SetPlayerData(player, data)
end

-- If player spend and earns the currency resource, update the storage
function OnResourceChanged(player, resource)
    if resource == RESOURCE_KEY then
        UpdateStorageBalance(player)
    end
end

-- If player's doing in game transactions, check and update
-- the balance for current currency with storage bundle tracking
function OnPerksChanged(player)
    CheckPerkCountWithStorage(player)
    UpdateStorageBalance(player)
end

-- Sets player resource from storage and connects player events
function OnPlayerJoined(player)
    local data = Storage.GetPlayerData(player)

    -- Setup player resource and save it in a table
    if not data[RESOURCE_KEY] or not data[RESOURCE_KEY].amount then
        data[RESOURCE_KEY] = {}
        data[RESOURCE_KEY].amount = 0
    end

    -- Setup current Perk purchased count per bundle
    for _, bundle in ipairs(bundles) do
        if not data[RESOURCE_KEY][bundle.storageId] or Environment.IsLocalGame() then
            data[RESOURCE_KEY][bundle.storageId] = player:GetPerkCount(bundle.perk)
        end
    end

    Storage.SetPlayerData(player, data)

    -- Set currency resource for displaying balance to player on client side
    player:SetResource(RESOURCE_KEY, data[RESOURCE_KEY].amount)

    -- Connect events that updates currency balance for player
    player.resourceChangedEvent:Connect(OnResourceChanged)
    player.perkChangedEvent:Connect(OnPerksChanged)
end

Game.playerJoinedEvent:Connect(OnPlayerJoined)

See also: Storage.GetPlayerData | Player.GetResource | Game.playerJoinedEvent | CoreObject.GetCustomProperty | Event.Connect


Example using:

perkChangedEvent

HasPerk

GetPerkCount

Perks are a system to create in-game purchases that allow players to support game creators and enable exclusive content.

Learn more about Perks here.

In the following example, a script is a child of a Perk Purchase Button, of type UIPerkPurchaseButton. The user interface container that has the button is in a client context. The specifics of the Perk come in through the custom property MyPerk, which is then assigned to the button with SetPerkReference(). When the player joins we connect to the perkChangedEvent and print out their existing perks with the LogPerks() function.

-- Perk Net Reference custom parameters
local MY_PERK = script:GetCustomProperty("MyPerk")
local TEST_LIMITED_TIME = script:GetCustomProperty("TestLimitedTime")
local TEST_PERMANENT = script:GetCustomProperty("TestPermanent")
local TEST_REPEATABLE = script:GetCustomProperty("TestRepeatable")

-- Mapping of PerkNetRefs to table of properties, in this case a name
local perkList = {}
perkList[TEST_LIMITED_TIME] = { name = "limited-time" }
perkList[TEST_PERMANENT] = { name = "permanent" }
perkList[TEST_REPEATABLE] = { name = "repeatable" }

-- Set purchase button's Perk to given custom property
script.parent:SetPerkReference(MY_PERK)

function DebugLog(msg)
    print(msg)
    UI.PrintToScreen(msg)
end

function OnPerkChanged(player, perkRef)
    DebugLog("on perks changed " .. player.name)

    if (perkList[perkRef] ~= nil) then
        DebugLog("perk changed: " .. perkList[perkRef].name)
    end

    LogPerks(player)
end

function LogPerks(player)
    -- Example of HasPerk() and GetPerkCount().
    -- For non-repeatable perks checking GetPerkCount() > 0
    -- is equivalent to HasPerk() == true
    for perkRef, prop in pairs(perkList) do
        DebugLog("-- perk: " .. prop.name)

        local hasPerkMsg = "    has perk?: " .. tostring(player:HasPerk(perkRef))
        local perkCountMsg = "    count: " .. tostring(player:GetPerkCount(perkRef))

        DebugLog(hasPerkMsg)
        DebugLog(perkCountMsg)

        -- Example of getting Perk reference of parent Perk button
        local parentPerkRef = script.parent:GetPerkReference()
        if (parentPerkRef.isAssigned and perkRef == parentPerkRef) then
            DebugLog("is parent perk ref")
        end
    end
end

function OnPlayerJoined(player)
    -- Connect perkChangedEvent
    player.perkChangedEvent:Connect(OnPerkChanged)

    -- Log perks player has initially on join
    LogPerks(player)
end

Game.playerJoinedEvent:Connect(OnPlayerJoined)

See also: UIPerkPurchaseButton.SetPerkReference | NetReference.isAssigned | Game.playerJoinedEvent | CoreObject.GetCustomProperty | Player.name | CoreLua.print | UI.PrintToScreen | Event.Connect



Last update: August 15, 2022