Help with turning limbs

Basically I want for my arms to turn along with the head and they must face the direction in which the head is looking. The issue I encountered is that halfway through the arms start going in a completely opposite direction.


As you can see, the arms start going down whenever I start looking up. I don’t know how to fix this due to the script being one of my very old ones and my knowledge on this topic is, let’s say, poor.

The script:

local RunService = game:GetService("RunService")

local camera = workspace.CurrentCamera
workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(function()
	local newCam = workspace.CurrentCamera
	if newCam then
		camera = newCam
	end
end)

local char:Model = script.Parent
local root:Part = char:WaitForChild("HumanoidRootPart")

local neck:Motor6D = char:FindFirstChild("Neck", true)
repeat wait(); neck = char:FindFirstChild("Neck", true) until neck ~= nil

local rightShoulder:Motor6D = char:FindFirstChild("Right Shoulder", true)
repeat wait(); rightShoulder = char:FindFirstChild("Right Shoulder", true) until rightShoulder ~= nil

local leftShoulder:Motor6D = char:FindFirstChild("Left Shoulder", true)
repeat wait(); leftShoulder = char:FindFirstChild("Left Shoulder", true) until leftShoulder ~= nil

local angles, asin = function(x, y, z, deg:boolean)
	if deg == nil then deg = false end
	local outX, outY, outZ
	if deg then
		outX, outY, outZ = math.rad(x), math.rad(y), math.rad(z)
	else
		outX, outY, outZ = x, y, z
	end
	return CFrame.Angles(outX, outY, outZ)
end, math.asin
local defaultOffset = neck.C0
local rsOffset = rightShoulder.C0
local lsOffset = leftShoulder.C0

RunService.RenderStepped:Connect(function(dt)
	local camDir = root.CFrame:ToObjectSpace(camera.CFrame).LookVector
	local cameraFactor = angles(0, 0, -asin(camDir.X)) * angles(-asin(camDir.Y), 0, 0)
	local rsCamera = angles(0, 0, -asin(camDir.Z))
	local lsCamera = angles(0, 0, asin(camDir.Z))
	
	neck.C0 = defaultOffset * cameraFactor
	rightShoulder.C0 = rsOffset * rsCamera
	leftShoulder.C0 = lsOffset * lsCamera
end)

Settled on using a map function for this issue.

local function map(n, start, stop, newStart, newStop, withinBounds)
	local value = ((n - start) / (stop - start)) * (newStop - newStart) + newStart

	if not withinBounds then
		return value
	end

	if newStart < newStop then
		return math.max(math.min(value, newStop), newStart)
	else
		return math.max(math.min(value, newStart), newStop)
	end
end

...

RunService.RenderStepped:Connect(function(dt)
	local camDir = root.CFrame:ToObjectSpace(camera.CFrame).LookVector
	local cameraFactor = angles(0, 0, -asin(camDir.X)) * angles(-asin(camDir.Y), 0, 0)
	
	neck.C0 = defaultOffset * cameraFactor
	rightShoulder.C0 = rsOffset * angles(0, 0, map(-neck.C0.LookVector.Z, -1, 1, 10, 160), true)
	leftShoulder.C0 = lsOffset * angles(0, 0, -map(-neck.C0.LookVector.Z, -1, 1, 10, 160), true)
	if tick()-lastFire >= fireDelay then
		lastFire = tick()
		turnRemote:FireServer(neck, neck.C0, rightShoulder, rightShoulder.C0, leftShoulder, leftShoulder.C0)
	end
end)

Though if anyone knows a mathematical solution, please tell me. I would still like to hear it to expand my knowledge on this topic.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.