Arms following mouse but resulting a curve motion

local runService = game:GetService("RunService")
local players = game:GetService("Players")
local userInputService = game:GetService("UserInputService")
local replicateStorage = game:GetService("ReplicatedStorage")

local lookRemote = replicateStorage.Remotes.Character.LookAt

local player = players.LocalPlayer
local mouse = player:GetMouse()

local character = player.Character or player.CharacterAdded:Wait()
local root = character:WaitForChild("HumanoidRootPart")
local humanoid = character:WaitForChild("Humanoid")
local torso = character:WaitForChild("Torso")

local rightShoulder = torso:WaitForChild("Right Shoulder")
local leftShoulder = torso:WaitForChild("Left Shoulder")
local neck = torso:WaitForChild("Neck")

local turnSpeed = 0.05
local aimingState = false

local RC0_Origin = CFrame.new(1, 0.5, 0, 0, 0, 1, 0, 1, 0, -1, 0, 0)
local LC0_Origin = CFrame.new(-1, 0.5, 0, 0, 0, -1, 0, 1, 0, 1, 0, 0)
local Neck_Origin = CFrame.new(0, 1, 0, -1, 0, 0, 0, 0, 1, 0, 1, -0)

local gunAttach 
local Gun_C0_Origin 
local Gun_C1_Origin

local HandOffset = CFrame.new(0, -0.5, -1) * CFrame.Angles(0, math.rad(-90), 0)

character:GetAttributeChangedSignal("Aiming"):Connect(function()
	aimingState = character:GetAttribute("Aiming")
	humanoid.AutoRotate = not aimingState

	if aimingState then
		gunAttach = torso:FindFirstChild("GunAttach")
		if gunAttach then
			Gun_C0_Origin = gunAttach.C0
			Gun_C1_Origin = gunAttach.C1
		end
	end

	if not aimingState then
		rightShoulder.C0 = RC0_Origin
		leftShoulder.C0 = LC0_Origin
		neck.C0 = Neck_Origin

		if gunAttach and Gun_C0_Origin and Gun_C1_Origin then
			gunAttach.C0 = Gun_C0_Origin
			gunAttach.C1 = Gun_C1_Origin
		end
	end
end)

runService.RenderStepped:Connect(function()
	if not aimingState then return end

	local hitPos = mouse.Hit.Position
	if not hitPos then return end
	local angle = math.asin(mouse.Origin.LookVector.Y)
	local rightArmRotation = RC0_Origin * CFrame.Angles(0, 0, angle)
	local leftArmRotation = LC0_Origin * CFrame.Angles(0, 0, -angle)
	local neckRotation = Neck_Origin * CFrame.Angles(-angle, 0, 0)

	rightShoulder.C0 = rightShoulder.C0:Lerp(rightArmRotation, turnSpeed)
	leftShoulder.C0 = leftShoulder.C0:Lerp(leftArmRotation, turnSpeed)
	neck.C0 = neck.C0:Lerp(neckRotation, turnSpeed)
		
	if gunAttach then
		gunAttach.C1 = CFrame.new() 
		gunAttach.C0 = rightShoulder.C0 * HandOffset
	end

	local flatTarget = Vector3.new(hitPos.X, root.Position.Y, hitPos.Z)
	local targetCF = CFrame.lookAt(root.Position, flatTarget)
	root.CFrame = root.CFrame:Lerp(targetCF, turnSpeed)
	
	--lookRemote:FireServer(angle)
end) 

Currently this is my code for the rotation, but somehow when i point up or down my arms would eventually got curved.

Ive read several posts, but could not found any solutions.

1 Like

so put a math.clamp() on how far the arms rotate

could you provide an example? I dont quite get it

local runService = game:GetService("RunService")
local players = game:GetService("Players")
local userInputService = game:GetService("UserInputService")
local replicateStorage = game:GetService("ReplicatedStorage")

local lookRemote = replicateStorage.Remotes.Character.LookAt

local player = players.LocalPlayer
local mouse = player:GetMouse()

local character = player.Character or player.CharacterAdded:Wait()
local root = character:WaitForChild("HumanoidRootPart")
local humanoid = character:WaitForChild("Humanoid")
local torso = character:WaitForChild("Torso")

local rightShoulder = torso:WaitForChild("Right Shoulder")
local leftShoulder = torso:WaitForChild("Left Shoulder")
local neck = torso:WaitForChild("Neck")

local turnSpeed = 0.05
local aimingState = false

local RC0_Origin = CFrame.new(1, 0.5, 0, 0, 0, 1, 0, 1, 0, -1, 0, 0)
local LC0_Origin = CFrame.new(-1, 0.5, 0, 0, 0, -1, 0, 1, 0, 1, 0, 0)
local Neck_Origin = CFrame.new(0, 1, 0, -1, 0, 0, 0, 0, 1, 0, 1, -0)

local gunAttach 
local Gun_C0_Origin 
local Gun_C1_Origin

local HandOffset = CFrame.new(0, -0.5, -1) * CFrame.Angles(0, math.rad(-90), 0)

character:GetAttributeChangedSignal("Aiming"):Connect(function()
	aimingState = character:GetAttribute("Aiming")
	humanoid.AutoRotate = not aimingState

	if aimingState then
		gunAttach = torso:FindFirstChild("GunAttach")
		if gunAttach then
			Gun_C0_Origin = gunAttach.C0
			Gun_C1_Origin = gunAttach.C1
		end
	end

	if not aimingState then
		rightShoulder.C0 = RC0_Origin
		leftShoulder.C0 = LC0_Origin
		neck.C0 = Neck_Origin

		if gunAttach and Gun_C0_Origin and Gun_C1_Origin then
			gunAttach.C0 = Gun_C0_Origin
			gunAttach.C1 = Gun_C1_Origin
		end
	end
end)

runService.RenderStepped:Connect(function()
	if not aimingState then return end

	local hitPos = mouse.Hit.Position
	if not hitPos then return end
	local angle = math.asin(mouse.Origin.LookVector.Y)
	local rightArmRotation = math.clamp(RC0_Origin * CFrame.Angles(0, 0, angle), RC0_Origin, CFrame.new(25, 20, 25)) -- idk at what point your arms start breaking so you could just change these CFrame coordinates.
	local leftArmRotation = math.clamp(LC0_Origin * CFrame.Angles(0, 0, -angle), RC0_Origin, CFrame.new(25, 20, 25)) -- same here.
	local neckRotation = Neck_Origin * CFrame.Angles(-angle, 0, 0) -- and if It ends up happening with the neck you could do the same thing.

	rightShoulder.C0 = rightShoulder.C0:Lerp(rightArmRotation, turnSpeed)
	leftShoulder.C0 = leftShoulder.C0:Lerp(leftArmRotation, turnSpeed)
	neck.C0 = neck.C0:Lerp(neckRotation, turnSpeed)
		
	if gunAttach then
		gunAttach.C1 = CFrame.new() 
		gunAttach.C0 = rightShoulder.C0 * HandOffset
	end

	local flatTarget = Vector3.new(hitPos.X, root.Position.Y, hitPos.Z)
	local targetCF = CFrame.lookAt(root.Position, flatTarget)
	root.CFrame = root.CFrame:Lerp(targetCF, turnSpeed)
	
	--lookRemote:FireServer(angle)
end)

Let me know if it works or not, I cant use my computer right now.

Math.clamp expected a number, not cframe
But i will send a video so it will let you know what really happened

External Media

Here is the video

local runService = game:GetService("RunService")
local players = game:GetService("Players")
local userInputService = game:GetService("UserInputService")
local replicateStorage = game:GetService("ReplicatedStorage")

local lookRemote = replicateStorage.Remotes.Character.LookAt

local player = players.LocalPlayer
local mouse = player:GetMouse()

local character = player.Character or player.CharacterAdded:Wait()
local root = character:WaitForChild("HumanoidRootPart")
local humanoid = character:WaitForChild("Humanoid")
local torso = character:WaitForChild("Torso")

local rightShoulder = torso:WaitForChild("Right Shoulder")
local leftShoulder = torso:WaitForChild("Left Shoulder")
local neck = torso:WaitForChild("Neck")

local turnSpeed = 0.05
local aimingState = false

local RC0_Origin = CFrame.new(1, 0.5, 0, 0, 0, 1, 0, 1, 0, -1, 0, 0)
local LC0_Origin = CFrame.new(-1, 0.5, 0, 0, 0, -1, 0, 1, 0, 1, 0, 0)
local Neck_Origin = CFrame.new(0, 1, 0, -1, 0, 0, 0, 0, 1, 0, 1, -0)

local gunAttach 
local Gun_C0_Origin 
local Gun_C1_Origin

local HandOffset = CFrame.new(0, -0.5, -1) * CFrame.Angles(0, math.rad(-90), 0)

character:GetAttributeChangedSignal("Aiming"):Connect(function()
	aimingState = character:GetAttribute("Aiming")
	humanoid.AutoRotate = not aimingState

	if aimingState then
		gunAttach = torso:FindFirstChild("GunAttach")
		if gunAttach then
			Gun_C0_Origin = gunAttach.C0
			Gun_C1_Origin = gunAttach.C1
		end
	end

	if not aimingState then
		rightShoulder.C0 = RC0_Origin
		leftShoulder.C0 = LC0_Origin
		neck.C0 = Neck_Origin

		if gunAttach and Gun_C0_Origin and Gun_C1_Origin then
			gunAttach.C0 = Gun_C0_Origin
			gunAttach.C1 = Gun_C1_Origin
		end
	end
end)

runService.RenderStepped:Connect(function()
	if not aimingState then return end

	local hitPos = mouse.Hit.Position
	if not hitPos then return end
	local angle = math.asin(mouse.Origin.LookVector.Y)

	local rightArmRotation = RC0_Origin * CFrame.Angles(0, 0, math.clamp(angle, 5, 30)
	local leftArmRotation = LC0_Origin * CFrame.Angles(0, 0, math.clamp(-angle, -5, -30)
	local neckRotation = Neck_Origin * CFrame.Angles(math.clamp(-angle, -5, -25), 0, 0) 
        -- adjust clamp minimum and maximum values as needed.

	rightShoulder.C0 = rightShoulder.C0:Lerp(rightArmRotation, turnSpeed)
	leftShoulder.C0 = leftShoulder.C0:Lerp(leftArmRotation, turnSpeed)
	neck.C0 = neck.C0:Lerp(neckRotation, turnSpeed)
		
	if gunAttach then
		gunAttach.C1 = CFrame.new() 
		gunAttach.C0 = rightShoulder.C0 * HandOffset
	end

	local flatTarget = Vector3.new(hitPos.X, root.Position.Y, hitPos.Z)
	local targetCF = CFrame.lookAt(root.Position, flatTarget)
	root.CFrame = root.CFrame:Lerp(targetCF, turnSpeed)
	
	--lookRemote:FireServer(angle)
end)

Let me know if this works, I’ve got one more solution in my head.

Well it does work, but not really what i wanted. Your script do limit the arm rotation but like the arms should be straighten when looking up or down, but it is doing a curve when the mouse point up or down.


This is my game

This is their

It does not curve

You could try lowering the Max Value on the Clamp to something other than the: 30, -30, -25 numbers to prevent it from going too far out

I tried a few value but it would keep limiting my character arms from going up. I dont think math.clamp is a solution

Are you making sure that the LookAt vector for the arms are pointed in the direction of the mouse.

I think so, isnt that is what the script are doing?


I managed to make the same effect in first person( from other people works ), otherwise in third person i literally have no idea.