Anchoring/Unanchoring During Animation Causes Assembly Center Of Mass Being Incorrectly Evaluated

When playing an animation (that moves the torso) and anchoring any part of the character, if you unanchor before the animation finishes (using Animation.Ended as a reference), the character’s assembly mass becomes incorrectly calculated.
This can cause unexpected physics behavior.

Visual Aids:
streamable

Reproduction Steps:

  1. Play an animation that moves the torso.
  2. Anchor any character part (e.g., HumanoidRootPart) while the animation is still playing.
  3. Unanchor the part before Animation.Ended fires.
  4. Observe mass and physics glitches.

Reproduction Files:
Roblox Place
Test Place (59,0 КБ)

Code to Reproduce:

local player = game:GetService("Players").LocalPlayer
local animation = game:GetService("ReplicatedStorage").Animation

game:GetService("UserInputService").InputBegan:Connect(function(input, isProcessed)
	if isProcessed then return end

	if input.KeyCode == Enum.KeyCode.T then
		local rootPart = player.Character:FindFirstChild("HumanoidRootPart")
		if not rootPart then return end
		local track = player.Character:FindFirstChildWhichIsA("Animator", true):LoadAnimation(animation)
		track:Play()

		rootPart.Anchored = true
		print("Anchored state: ".. tostring(rootPart.Anchored))
		task.wait(0.5)
		rootPart.Anchored = false
		print("Anchored state: ".. tostring(rootPart.Anchored))
	end
end)

Additional Information:

  • Happens both in Studio and live games.
  • Still happens with all plugins disabled.
  • No browser or user-specific factors involved.

Expected behavior

Character’s assembly and physics behavior should remain stable after anchoring/unanchoring, regardless of animations playing.

3 Likes

I was unsure if this deserved a separate bug report, but the same issue also occurs by using a combination of tools and emotes

how to replicate:

  • join any game with emotes/custom player animations & tools
  • preform any emote, the farther away the arms move from the center the better
  • equip/unequip the tool at that position
  • this will move your character’s center of mass

this bug also works in r6

This can easily be abused as a speed glitch in games: (devs implemented a hacky patch in this one)

The hacky patch in question, this was posted publicly in the game's discord: This client-sided code removes all tools from the backpack while doing a blacklisted emote
local player = game.Players.LocalPlayer
local character = script.Parent 
local humanoid = character:WaitForChild("Humanoid")
local animator = humanoid:WaitForChild("Animator")
local hidebackpack = player:WaitForChild("hidebackpack")

local nobackpackanims = {
    10214319518, -- v pose
    14352343065,
    11453082181,
    10714076981,
    14024642130,
    10370351535,
    10714342957,
    10275008655,
    10714383856,
    10714336041,
    10714395175,
    12992262118,
    10714345459,
    10714389396,
    11753474067,
    10214406616,
    15505459811,
    15609995579,
    97311229290836,
    14123781004,
}

local set=string.split(hidebackpack.Value,",")
set[8]="0"
hidebackpack.Value=table.concat(set,",")

local function CheckAnims()
    local nobackpack = false
    local animationtracks = animator:GetPlayingAnimationTracks() 
    for _, animationtrack in pairs(animationtracks) do
        local animobject = animationtrack.Animation
        for i, v in pairs(nobackpackanims) do
            if string.match(animobject.AnimationId, tostring(v)) then
                nobackpack = true
                break
            end
        end
    end
    if nobackpack then
        backpackhidden = true
        local set=string.split(hidebackpack.Value,",")
        set[8]="1"
        hidebackpack.Value=table.concat(set,",")
    else
        backpackhidden = false
        local set=string.split(hidebackpack.Value,",")
        set[8]="0"
        hidebackpack.Value=table.concat(set,",")
    end
end

animator.AnimationPlayed:Connect(function(animationtrack)
    local animobject = animationtrack.Animation
    local nobackpack = false
    for i, v in pairs(nobackpackanims) do
        if string.match(animobject.AnimationId, tostring(v)) then
            nobackpack = true
            break
        end
    end
    if nobackpack then
        CheckAnims()
        while backpackhidden do
            wait()
            CheckAnims()
        end
    elseif backpackhidden then
        CheckAnims()
    end
end)
2 Likes
1 Like