Setting neck C0 will move the torso and HumanoidRootPart instead of the Head

Hi devforum, I am having an issue trying to make a fps camera similar to the one in Beaks. I got the “shift lock” implementation down thanks to this amazing article

However when adding my own code to change the Neck joint to look in the direction im facing, I encountered a weird issue where the Root part will rotate instead of the head itself

RS.RenderStepped:Connect(function()
	local Character = game.Players.LocalPlayer.Character
	if not Character then return end
	local Humanoid = Character:FindFirstChildOfClass("Humanoid")
	local HRP = Character.PrimaryPart
	local Head = Character:FindFirstChild("Head")
	local Torso = Character:FindFirstChild("Torso")
	if not Humanoid or not HRP or not Head or not Torso then return end
	local RS = game:GetService("RunService")
	
	local target = workspace.CurrentCamera.CFrame.Rotation:ToEulerAnglesYXZ()
	
	target = target * TorsoLock.EnabledAlpha.Value
	
	local NeckJoint = Torso:FindFirstChild("Neck")
	if NeckJoint then
		local nx, ny, nz = NeckJoint.C0:ToEulerAnglesXYZ()

		NeckJoint.C0 = CFrame.new(NeckJoint.C0.Position) * CFrame.Angles(target - math.rad(90), ny, nz)
	end		
end)

This is the code that is responsible for rotating the neck


and this is the result

I narrowed down the bug down to my ShiftLock controller

RS:BindToRenderStep("ShiftLock", Enum.RenderPriority.Camera.Value - 1, function()
	local Character = game.Players.LocalPlayer.Character
	if not Character then return end
	local Humanoid = Character:FindFirstChildOfClass("Humanoid")
	local HRP = Character.PrimaryPart
	local Head = Character:FindFirstChild("Head")
	if not Humanoid or not HRP or not Head then return end
		
	local isZoomedIn = ((Head.Position + HRP.CFrame.Rotation:VectorToWorldSpace(Humanoid.CameraOffset)) - workspace.CurrentCamera.CFrame.Position).Magnitude < 1
		
	if isZoomedIn then
		Humanoid.CameraOffset = Vector3.zero
		Humanoid.AutoRotate = true
		return
	end
		
	Humanoid.CameraOffset = CAMERA_OFFSET * PsuedoShiftLock.EnabledAlpha.Value
		
	if PsuedoShiftLock.EnabledAlpha.Value ~= 0 then
		Humanoid.AutoRotate = true
		local x, y, z = workspace.CurrentCamera.CFrame.Rotation:ToEulerAnglesYXZ()
		--commenting out the line below fixes the issue
		HRP.CFrame = CFrame.new(HRP.Position) * CFrame.Angles(0, y, 0)
	else
		
		Humanoid.AutoRotate = true
	end
end)

I have tried all different combinations of render orders, where the shift lock runs before and after the look order, messed around with render functions before and after physics simulation

I have also tried using PivotTo() instead of the CFrame.new() shown

1 Like

Apologies I stumbled upon my answer, Apparently for R6 rigs, the PrimaryPart is the Head instead of the HumanoidRootPart.

This meant instead of moving the HumanoidRootPart like I intended, I was actually moving the head.