This change is now enabled globally and the Studio Beta Feature is no longer available. The original announcement and details of the change are below.
Currently the behavior of Motor6D
s have some interesting frustrating edge cases. We’re going to fix that. Fixing this may impact some games that were relying on the edge case functionality.
If you are using Motor6D and animating Motor6D.Transform
in models that you rigged yourself or with third-party tools and happen to be using Motor6Ds “backwards”, your game may be affected. Soon they will be not-backwards, which might mean “backwards” for you.
The legacy CurrentAngle
and DesiredAngle
properties of Motor6D
inherited from Motor
are also affected in the same way. The behavior of CurrentAngle
on Motor
itself is unaffected.
All of our canonical Humanoid rigging creates Motor6Ds with the “parent” part as Part0 and the “child” part as Part1, e.g. “RightKnee” has RightUpperLeg as Part0 and RightLowerLeg as Part1. If automatic Humanoid rigging or Humanoid.BuildRigFromAttachments
is the only way you’re creating Motor6Ds you will not be affected. If you’ve created Motor6Ds yourself manually or with third party tools you may be affected, and should try your games with the Studio Beta Feature enabled (instructions below) to make sure the motors in your game behave as expected.
What’s the Problem? What’s Changing Changed?
Previously, the devhub almost correctly describes the joint relationship of a Motor6D:
Transform is the transformation between the “parent” part and the “child” part. The “parent” part will always be the part that is more directly connected to
JointInstance.C0the assembly root part defined byBasePart:GetRootPart()
. This is not affected by which part is assigned toJointInstance.Part0
and which isJointInstance.Part1
. If the side the root part is on changes the interpretation of Transform will be inverted.Similar to a WeldJoint, an active Motor6D will rigidly hold its two parts such that:
PartParent.CFrame * CParent * Transform == PartChild.CFrame * Child
I helped write that and this is behavior still confusing to me. It’s excessively complicated, and as a developer you have no easy way to tell what the real “parent” and “child” are in this context. You have to assume. You shouldn’t need to worry about this. That’s our job.
Still, this generally works. Until you do something reasonable like string a RopeConstraint between an R15’s foot or hand and an anchored part. The anchored part will become the mechanism root, and the character’s foot will become the R15’s GetRootPart()
“Assembly” root instead of HumanoidRootPart. Internally, all of the character’s parts will now be positioned relative to the foot instead of the HumanoidRootPart, and the foot now becomes the “parent” of the lower leg instead of the other way around. Now the direction of LeftFoot.LeftAnkle.Transform
is inverted.
Animator always assumes Part0 is the parent part in the internal transform hierarchy used to calculate final part positions, but if this isn’t the case the Animator will not compensate for this and your limbs can end up with a “backwards” inverse rotation.
We fixed this to have consistent behavior, regardless of the direction of the internal low-level transform hierarchy built from rigid joints. This way the scenario above won’t kneecap you or your characters, and you’ll never have to think about this nonsense again.
The simplified behavior is:
While the Motor6D is
Active
, it maintains the part positions such that:
Part0.CFrame * C0 * Transform == Part1.CFrame * C1
Much simpler. No more backwards knees.
As before, Transform is not immediately applied when it is changed by Animators or scripts. It is only applied once per frame after RunService.Stepped
, right before physics simulates for the frame. This deferred update behavior makes modifying Transform
very cheap compared to updating C0
or C1
of a Motor6D or any other kind of Weld-like joint when you are updating them every frame.
All of the above also applies to the MaxVelocity
, CurrentAngle
and DesiredAngle
properties of Motor6D
in the same way.
I Create My Own Motor6Ds and Might Be Affected…
This change is now enabled globally and the Studio Beta Feature is no longer available.
If you think this change might affect you, you can enable it now in Studio Beta Features:
If joints look backwards after enabling this try swapping Part0 and Part1 and fixing any scripts that might update those Transforms to use the Inverse()
of that CFrame instead.
In most cases you should be able to publish any fixes to your game immediately, without waiting for this change to release.
When is This Changing?
This change was enabled globally on Tuesday, April 21st at 4:14 PM, PST.
We’re going to enable this change globally on Monday, April 20th.