Part Welded to Character not CFraming Correctly

Alright guys, I have a problem where I try to move an assembly of welded parts (including the HumanoidRootPart) using CFrame and it does not go where I want it to. If I try to set any part’s CFrame, it acts as if I tried to set the HumanoidRootPart’s CFrame instead for that position.

Here’s a fairly simple repro which goes in a LocalScript in StarterCharacterScripts.

Code Repro & Output (inlined with the code)
--[[

This script welds a part right below a Character's feet, then moves it around via CFrame.

--]]

wait(1); --wait for the character to spawn

local p = Instance.new("Part");
p.Size = Vector3.new(4, 1, 4);
p.CanCollide = false;
p.Parent = workspace;

local w = Instance.new("Weld");
w.Part0 = p;
w.Part1 = game.Players.LocalPlayer.Character.HumanoidRootPart;
w.C0 = CFrame.new(0, .5, 0);
w.C1 = CFrame.new(0, -3, 0);
w.Parent = p;

local theta = 0; --radians
game:GetService("RunService").Heartbeat:connect(function(dt)
	theta = theta + dt;
	p.CFrame = CFrame.new(math.cos(theta) * 10, .5, math.sin(theta) * 10);
	print("Part was placed " .. tostring(.5 - p.Position.y) .. " studs below desired");
	--> Part was placed 3.5 studs below desired
end)

The result is that the part welded to the character’s feet (which should be 3.5 studs below the character) gets offset by 3.5 studs.


The workaround is fairly clear, but before I jump through hoops to work around this, is there anything obvious I’m doing wrong? Is this just documented behavior that setting the CFrame of anything welded to the HRP will act as if you instead set the CFrame of the HRP?

image

You’ve ran into a backwards compatibility quirk!

Back when the HumanoidRootPart was introduced, Roblox made it so attempting to CFrame any other part of a Humanoids joint assembly would be directed to the HumanoidRootPart.

I speculate they did this so that old character teleporting code wouldn’t break the HumanoidRootPart. Under normal circumstances, directly writing to a part’s CFrame will break any parenting joint that interferes with the parts motion. Older teleporting code would set the Torso’s CFrame directly, and thus would break the HumanoidRootPart away from the Torso. It would require everyone to update their scripts and tools to use the HumanoidRootPart instead, which would be a mess to say the least.

In most cases this isn’t an issue because people aren’t usually manipulating the CFrame of a limb directly, but clearly you’re doing something out of the norm here. One way to work around this issue is to multiply the CFrame of whatever part you’re manipulating by the inverse object space between that part and the HumanoidRootPart.

(This is what Roblox should be doing in the first place when it does this HumanoidRootPart redirect, but apparently it’s not)

3 Likes

Alright, thanks for the context.

Is this something that can be found on the wiki? Alternately, is this forum publicly searchable/viewable?


I’ve already implemented my workaround, I’m just wondering if we’re doomed to have every developer discover this same mystery on their own.

I could really get behind this.

Some sections are. I was able to find this through a search in a private/incognito window:

It looks like results also show up in Google (try searching welding parts to a character anchors it), but this thread doesn’t show up since Google hasn’t gotten to it yet.