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.
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.
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)