Skip to content

AnimatedMesh

AnimatedMesh objects are skeletal CoreMeshes with parameterized animations baked into them. They also have sockets exposed to which any CoreObject can be attached.

Properties

Property Name Return Type Description Tags
animationStance string The stance the animated mesh plays. Read-Write, Client-Only
animationStancePlaybackRate number The playback rate for the animation stance being played. Read-Write, Client-Only
animationStanceShouldLoop boolean If true, the animation stance will keep playing in a loop. If false the animation will stop playing once completed. Read-Write, Client-Only
playbackRateMultiplier number Rate multiplier for all animations played on the animated mesh. Setting this to 0 will stop all animations on the mesh. Read-Write, Client-Only

Functions

Function Name Return Type Description Tags
GetAnimationNames() Array<string> Returns an array of all available animations on this object. None
GetAnimationStanceNames() Array<string> Returns an array of all available animation stances on this object. None
GetSocketNames() Array<string> Returns an array of all available sockets on this object. None
GetAnimationEventNames(string animationName) Array<string> Returns an array of available animation event names for the specified animation. Raises an error if animationName is not a valid animation on this mesh. None
AttachCoreObject(CoreObject objectToAttach, string socketName) None Attaches the specified object to the specified socket on the mesh if they exist. Client-Only
PlayAnimation(string animationName, [table parameters]) None Plays an animation on the animated mesh.
Optional parameters can be provided to control the animation playback: startPosition (number): A number between 0 and 1 controlling where in the animation playback will start; playbackRate (number): Controls how fast the animation plays; shouldLoop (boolean): If true, the animation will keep playing in a loop. If false the animation will stop playing once completed.
Client-Only
StopAnimations() None Stops all in-progress animations played via PlayAnimation on this object. Client-Only
GetAnimationDuration(string animationName) number Returns the duration of the animation in seconds. Raises an error if animationName is not a valid animation on this mesh. None
GetMeshForSlot(integer slotIndex) string Returns the asset ID of the mesh assigned to the specified slot on this AnimatedMesh. Returns nil if no mesh is assigned to the slot. Client-Only
SetMeshForSlot(integer slotIndex, string assetId) None Assigns a mesh to the specified slot on this AnimatedMesh. If assetId is an empty string or identifies an incompatible asset, the slot will be cleared. Client-Only
SetMaterialForSlot(string assetId, string slotName) None Set the material in the given slot to the material specified by assetId. None
GetMaterialSlot(string slotName) MaterialSlot Get the MaterialSlot object for the given slot. If called on the client on a networked object, the resulting object cannot be modified. None
GetMaterialSlots() Array<MaterialSlot> Get an array of all MaterialSlots on this mesh. If called on the client on a networked object, the resulting object cannot be modified. None
ResetMaterialSlot(string slotName) None Resets a material slot to its original state. None

Events

Event Name Return Type Description Tags
animationEvent Event<AnimatedMesh animatedMesh, string eventName, string animationName> Some animations have events specified at important points of the animation (e.g. the impact point in a punch animation). This event is fired with the animated mesh that triggered it, the name of the event at those points, and the name of the animation itself. Client-Only

Examples

Example using:

animationEvent

Some animations have events that fire when certain parts of the animations are reached. This allows you to sync up hit effects with animations. Important note! This event is only fired client side. The server cannot directly respond to animation events!

local propDragonMob = script:GetCustomProperty("DragonMob")
local dragonMesh = World.SpawnAsset(propDragonMob)

function AnimEventListener(mesh, eventName)
    print("Animated Mesh " .. mesh.name .. " just hit event " .. eventName .. "!")
    -- Normally we'd spawn a "Swipe" effect here, and possibly check if we hit a player!
end

dragonMesh.animationEvent:Connect(AnimEventListener)
dragonMesh:PlayAnimation("unarmed_claw")

See also: CoreObject.GetCustomProperty | World.SpawnAsset | AnimatedMesh.PlayAnimation | CoreLua.print


Example using:

AttachCoreObject

Attaches the specified object to the specified socket on the mesh if they exist.

In this example, we want to attach multiple objects to an animated mesh to create a costume, such as equipment on a skeleton enemy or horns on the head of a raptor. For it to work, setup the animated mesh in its "binding" stance and without any animations playing at the start. Place this script along with any costume parts to be attached as children of the animated mesh. Position and rotate the costume parts to align them with their destinations on the mesh. The costume parts are expected to be groups/folders with their names matching the socket names they are destined to. When the script runs, it searches through all the mesh's children and attaches them to the sockets.

local MESH = script.parent

local allObjects = MESH:GetChildren()

for _, obj in ipairs(allObjects) do
    if obj:IsA("Folder") then
        local socketName = obj.name
        local pos = obj:GetWorldPosition()
        local rot = obj:GetWorldRotation()

        MESH:AttachCoreObject(obj, socketName)

        obj:SetWorldPosition(pos)
        obj:SetWorldRotation(rot)
    end
end

See also: CoreObject.parent | other.IsA


Example using:

GetAnimationNames

GetAnimationStanceNames

GetSocketNames

GetAnimationEventNames

GetAnimationDuration

You can find out most of the interesting data about an Animated Mesh at runtime, using several handy functions.

local propDragonMob = script:GetCustomProperty("DragonMob")

-- This function prints out all of the animations, sockets, stances, and events associated
-- with an animated mesh!
function PrintAnimatedMeshData(mesh)
    print("Animation names:")
    for _, v in ipairs(mesh:GetAnimationNames()) do
        print("    " .. v .. "(" .. tostring(mesh:GetAnimationDuration(v)) .. ")")
        -- Print out any events that are associated with this animation:
        for _,e in ipairs(mesh:GetAnimationEventNames(v)) do
            print("        Event: " .. e)
        end
    end
    print("\nAnimation stance names:")
    for _, v in ipairs(mesh:GetAnimationStanceNames()) do
        print("    " .. v)
    end
    print("\nSocket names:")
    for _, v in ipairs(mesh:GetSocketNames()) do
        print("    " .. v)
    end
end

local dragonMesh = World.SpawnAsset(propDragonMob)
PrintAnimatedMeshData(dragonMesh)

See also: CoreObject.GetCustomProperty | World.SpawnAsset | CoreLua.print


Example using:

GetMeshForSlot

SetMeshForSlot

In this example, a client script copies the mesh slots from one AnimatedMesh to another.

local ANIM_MESH_1 = script:GetCustomProperty("AnimMesh1"):WaitForObject()
local ANIM_MESH_2 = script:GetCustomProperty("AnimMesh2"):WaitForObject()

function Clear(animMesh)
    animMesh:SetMeshForSlot(1, "")
    animMesh:SetMeshForSlot(2, "")
    animMesh:SetMeshForSlot(3, "")
    animMesh:SetMeshForSlot(4, "")
end

function CopyMeshAtSlot(slotIndex)
    local mesh = ANIM_MESH_1:GetMeshForSlot(slotIndex)
    if mesh then
        ANIM_MESH_2:SetMeshForSlot(slotIndex, mesh)
    end
end

Clear(ANIM_MESH_2)

CopyMeshAtSlot(1)
CopyMeshAtSlot(2)
CopyMeshAtSlot(3)
CopyMeshAtSlot(4)

See also: CoreObject.GetCustomProperty | CoreObjectReference.WaitForObject


Example using:

PlayAnimation

playbackRateMultiplier

Plays an animation on the animated mesh. Optional parameters can be provided to control the animation playback: playbackRate (Number): Controls how fast the animation plays. shouldLoop (bool): If true, the animation will keep playing in a loop. If false the animation will stop playing once completed.

In this example, a humanoid animated mesh has its laughing and death animations controlled by pressing the primary and secondary action bindings (PC default is mouse left-click and right-click respectively).

local MESH = script.parent

function PlayAttack()
    MESH:PlayAnimation("unarmed_laugh")
    MESH.playbackRateMultiplier = 1
end

function PlayDeath()
    MESH:PlayAnimation("unarmed_death")
    Task.Wait(1.96)
    -- Prevents the animation from looping or returning to stance
    MESH.playbackRateMultiplier = 0
end

function OnBindingPressed(player, action)
    if action == "ability_primary" then
        PlayAttack()

    elseif action == "ability_secondary" then
        PlayDeath()
    end
end

Game.playerJoinedEvent:Connect(function(player)
    player.bindingPressedEvent:Connect(OnBindingPressed)
end)

See also: CoreObject.parent | Task.Wait | Game.playerJoinedEvent | Player.bindingPressedEvent | Event.Connect


Example using:

StopAnimations

You can stop whatever animation is currently playing via StopAnimations().

local propDragonMob = script:GetCustomProperty("DragonMob")
local dragonMesh = World.SpawnAsset(propDragonMob)

dragonMesh:PlayAnimation("unarmed_slash")
Task.Wait(0.25)
dragonMesh:StopAnimations()

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


Example using:

GetMaterialSlot

ResetMaterialSlot

In this example an NPC's body material is temporarily set to very bright when the functionShowStatusColor() is called. After a little time, it's set back to normal. We keep count of active status effects with the variable statusCount, so in case multiple calls to show the status color overlap during the wait time the material is not reset prematurally.

local ANIM_MESH = script.parent
local SLOT_NAME = "0:Shared_BaseMaterial"
local DURATION = 1.5
local statusCount = 0

function ShowStatusColor()
    local slot = ANIM_MESH:GetMaterialSlot(SLOT_NAME)
    if slot then
        slot:SetColor(Color.WHITE * 10) --Very bright

        statusCount = statusCount + 1
        Task.Wait(DURATION)
        statusCount = statusCount - 1

        if statusCount <= 0 then
            ANIM_MESH:ResetMaterialSlot(SLOT_NAME)
        end
    else
        print("No slot found with name " .. SLOT_NAME)
    end
end

See also: MaterialSlot.SetColor | Color.WHITE | Task.Wait | CoreObject.parent


Example using:

GetMaterialSlots

SetMaterialForSlot

In this example an NPC's material is changed at runtime. The script is placed as a child of the NPC's animated mesh and the desired material is assigned to the script as a custom property.

local ANIM_MESH = script.parent
local MATERIAL = script:GetCustomProperty("Material")

local matSlot = ANIM_MESH:GetMaterialSlots()[1]
ANIM_MESH:SetMaterialForSlot(MATERIAL, matSlot.slotName)

See also: MaterialSlot.slotName | CoreObject.parent


Example using:

animationStance

animationStancePlaybackRate

animationStanceShouldLoop

The stance the animated mesh plays.

This example demonstrates how to dynamically control the walking stances and to vary their playback speed by how fast the character is moving. This script itself does not move the mesh--that is expected to happen in another script such as an AI or simple MoveTo().

local MESH = script.parent

-- 0.9 is an approximate scale for the Fox mesh
-- 2 is an approximate for the Raptor and humanoids
local WALK_SCALE = 2

local RUN_BASE = 0.5
local RUN_SCALE = 0.002

-- Thresholds of speed (cm/s) that define which stance to use
local WALKING_SPEED = 15
local RUNNING_SPEED = 300

local lastPos = MESH:GetWorldPosition()

function Tick(deltaTime)
    if deltaTime <= 0 then return end

    local pos = MESH:GetWorldPosition()
    local direction = pos - lastPos
    local speed = direction.size / deltaTime

    -- We can make sure the animation stance loops. If we wanted it to only
    -- play once, we would set it to false here.
    MESH.animationStanceShouldLoop = true

    lastPos = pos

    if speed < WALKING_SPEED then
        MESH.animationStance = "unarmed_idle_ready"

    elseif speed < RUNNING_SPEED then
        MESH.animationStance = "unarmed_walk_forward"
        MESH.animationStancePlaybackRate = WALK_SCALE * (speed - WALKING_SPEED) / (RUNNING_SPEED - WALKING_SPEED)
    else
        MESH.animationStance = "unarmed_run_forward"
        MESH.animationStancePlaybackRate = RUN_BASE + (speed - RUNNING_SPEED) * RUN_SCALE
    end
end

See also: CoreObject.parent | Vector3 - Vector3 | CoreLua.Tick



Last update: December 2, 2021