Motor6D problems with procedural animations

I’ve been working on a script to procedurally rotate R15 rigs in your walking direction while in shift lock! Currently this works well for the LowerTorso and Legs via the Hip Motor6D’s, but my go to method here is not working when I try to rotate the C0 on the Left/Right Shoulder Motor6D’s.

Here’s the issue:
For each Motor6D, I run a calculation in RenderStepped to create a new CFrame to lerp the C0 to. This is performed after the animation is calculated (via RenderStepped), and then applied to the frame. For the Shoulder Motor6D’s, changing the C0’s CFrame Y-axis rotation value doesn’t rotate the arms by the expected 45 degrees, it just rotates them about 2 degrees on the Z-axis.

Script (apologies for all of the debug checks):

-- Services
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

-- References
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local HRP = Character:WaitForChild("HumanoidRootPart")
local LowerTorso = Character:WaitForChild("LowerTorso")
local UpperTorso = Character:WaitForChild("UpperTorso")
local Head = Character:WaitForChild("Head")
local RightLeg = Character:WaitForChild("RightUpperLeg")
local LeftLeg = Character:WaitForChild("LeftUpperLeg")
local RightArm = Character:WaitForChild("RightUpperArm")
local LeftArm = Character:WaitForChild("LeftUpperArm")

-- Original C0 Reference
local RootJointOriginalC0 = LowerTorso.Root.C0
local WaistOriginalC0 = UpperTorso.Waist.C0
local NeckOriginalC0 = Head.Neck.C0
local RightHipOriginalC0 = RightLeg.RightHip.C0
local RightKneeOriginalC0 = Character.RightLowerLeg.RightKnee.C0
local LeftHipOriginalC0 = LeftLeg.LeftHip.C0
local LeftKneeOriginalC0 = Character.LeftLowerLeg.LeftKnee.C0
local RightShoulderOriginalC0 = RightArm.RightShoulder.C0
local RightElbowOriginalC0 = Character.RightLowerArm.RightElbow.C0
local LeftShoulderOriginalC0 = LeftArm.LeftShoulder.C0
local LeftElbowOriginalC0 = Character.LeftLowerArm.LeftElbow.C0

local PlayersTable = {}

-- Settings
local RANGE_MOTION = 45
local TORSO_RANGE_MOTION = 90 - RANGE_MOTION
local RANGE_MOTION_XZ = RANGE_MOTION / 140	-- og 140
local LERP_SPEED = 0.005


RANGE_MOTION = math.rad(RANGE_MOTION)
TORSO_RANGE_MOTION = math.rad(TORSO_RANGE_MOTION)


function Calculate(dt, char)
	local HRP = char.HumanoidRootPart
	local LowerTorso = char.LowerTorso
	local UpperTorso = char.UpperTorso
	local Head = char.Head
	local RightLeg = char.RightUpperLeg
	local LeftLeg = char.LeftUpperLeg
	local RightArm = char.RightUpperArm
	local LeftArm = char.LeftUpperArm
	
	local DirectionOfMovement = HRP.CFrame:VectorToObjectSpace(HRP.AssemblyLinearVelocity)
	DirectionOfMovement = Vector3.new(DirectionOfMovement.X / char.Humanoid.WalkSpeed, 0, DirectionOfMovement.Z / char.Humanoid.WalkSpeed)
	
	local XResult = (DirectionOfMovement.X * (RANGE_MOTION - (math.abs(DirectionOfMovement.Z) * (RANGE_MOTION / 2))))
	local XResultTorso = (DirectionOfMovement.X * (TORSO_RANGE_MOTION - (math.abs(DirectionOfMovement.Z) * (TORSO_RANGE_MOTION / 2))))
	local XResultXZ = (DirectionOfMovement.X * (RANGE_MOTION_XZ - (math.abs(DirectionOfMovement.Z) * (RANGE_MOTION_XZ / 2))))
	
	if DirectionOfMovement.Z > 0.1 then
		-- Walking backwards
		XResult *= -1
		XResultTorso *= -1
		XResultXZ *= -1
	end
	
	local RightHipResult = RightHipOriginalC0 * CFrame.Angles(0, -XResult, 0)
	local RightKneeResult = RightKneeOriginalC0 * CFrame.Angles(0, -XResult, 0)
	
	local LeftHipResult = LeftHipOriginalC0 * CFrame.Angles(0, -XResult, 0)
	local LeftKneeResult = LeftKneeOriginalC0 * CFrame.Angles(0, -XResult, 0)
	
	local RootJointResult = RootJointOriginalC0 * CFrame.Angles(0, -XResultTorso, 0)
	local WaistResult = WaistOriginalC0 * CFrame.Angles(0, -XResultTorso, 0)
	local NeckResult = NeckOriginalC0 * CFrame.Angles(0, XResultTorso, 0)
	
	local LeftArmResult = LeftShoulderOriginalC0 * CFrame.Angles(0, XResultTorso, 0)
	local LeftElbowResult = LeftElbowOriginalC0 * CFrame.Angles(0, XResultTorso, 0)
	
	local RightArmResult = RightShoulderOriginalC0 * CFrame.Angles(0, XResultTorso, 0)
	local RightElbowResult = RightElbowOriginalC0 * CFrame.Angles(0, XResultTorso, 0)
	
	local LerpTime = 1 - LERP_SPEED ^ dt
	
	RightLeg.RightHip.C0 = RightLeg.RightHip.C0:Lerp(RightHipResult, LerpTime)
	
	LeftLeg.LeftHip.C0 = LeftLeg.LeftHip.C0:Lerp(LeftHipResult, LerpTime)
	
	LowerTorso.Root.C0 = LowerTorso.Root.C0:Lerp(RootJointResult, LerpTime)
	
        RightArm.RightShoulder.C0 = RightArm.RightShoulder.C0:Lerp(RightArmResult, LerpTime)
	--char.RightLowerArm.RightElbow.C0 = char.RightLowerArm.RightElbow.C0:Lerp(RightElbowResult, LerpTime)
	LeftArm.LeftShoulder.C0 = LeftArm.LeftShoulder.C0:Lerp(LeftArmResult, LerpTime)
	--char.LeftLowerArm.LeftElbow.C0 = char.LeftLowerArm.LeftElbow.C0:Lerp(LeftElbowResult, LerpTime)
	
end

RunService.RenderStepped:Connect(function(dt)
	
	for _, player in Players:GetPlayers() do
		if player.Character == nil then continue end
		if table.find(PlayersTable, player) then continue end
		table.insert(PlayersTable, player)
	end
	
	for i, player in pairs(PlayersTable) do
		if player == nil then
			table.remove(PlayersTable, i)
			continue
		end
		if Players:FindFirstChild(player.Name) == nil then
			table.remove(PlayersTable, i)
			continue
		end
		if player.Character == nil then
			table.remove(PlayersTable, i)
			continue
		end
		if player.Character:FindFirstChild("Humanoid").Health <= 0 then
			table.remove(PlayersTable, i)
			continue
		end
		
		local HumanoidRootPart = player.Character:FindFirstChild("HumanoidRootPart")
		local Humanoid = player.Character:FindFirstChild("Humanoid")
		local LowerTorso = player.Character:FindFirstChild("LowerTorso")
		local UpperTorso = player.Character:FindFirstChild("UpperTorso")
		local Head = player.Character:FindFirstChild("Head")
		local RightLeg = player.Character:FindFirstChild("RightUpperLeg")
		local LeftLeg = player.Character:FindFirstChild("LeftUpperLeg")
		local RightArm = player.Character:FindFirstChild("RightUpperArm")
		local LeftArm = player.Character:FindFirstChild("LeftUpperArm")
		
		if HumanoidRootPart == nil or Humanoid == nil or LowerTorso == nil then continue end
		if Head == nil or RightLeg == nil or LeftLeg == nil then continue end
		if RightArm == nil or LeftArm == nil then continue end
		
		task.spawn(Calculate, dt, player.Character)
	end
	
end)

This script is in StarterCharacterScripts.

Image of problem:
Bad Rotation 1
^ The LowerTorso and Legs are rotated correctly here, but the arms continue facing forward like in the animation (default run animation). They aren’t correctly rotating 45 degrees to match the LowerTorso.

So far I’ve tried playing around with the RANGE_MOTION constants, using positive or negative rotation values, but it seems like editing the Y-axis rotation of the CFrame just doesn’t work on the shoulder Motor6D’s like it does on all the other ones.

Any help would be much appreciated. It’s hard to find information on specific features of Motor6D’s, the docs are not super detailed on how attachments or parts affect the CFrames, or how rotation calculations can affect that.

1 Like