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:
^ 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.