How would I make my character's arms face the same way as the camera?

Hi there,

I’m making a third-person shooter and I’m playing an animation on my character’s arms. However, I want it so that as I look upwards and downwards, the arms actually stay sort of parallel with my camera. Is there a mathematical approach to this, or does anybody have a resource that could help me?

Thanks in advance!

PS: I’ve tried all of the posts on the DevForum and Youtube video’s, but could not get it to work properly.

A good place to start would be using some quick and simple trig to find the angle of the camera relative to the horizontal axis and applying that angle to the angle of the shoulder joint. To do this you could do the following

local runServ = game:GetService("RunService")

local plr = game.Players.LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()

runServ.RenderStepped:Connect(function()

    char:WaitForChild("RightUpperArm").RightShoulder.C1 = CFrame.new(char.RightUpperArm.RightShoulder.C1.Position) * CFrame.Angles(math.asin(-workspace.CurrentCamera.CFrame.LookVector.Y), 0, 0)

    char:WaitForChild("LeftUpperArm").LeftShoulder.C1 = CFrame.new(char.LeftUpperArm.LeftShoulder.C1.Position) * CFrame.Angles(math.asin(-workspace.CurrentCamera.CFrame.LookVector.Y), 0, 0)

end)

The code is only partially tested and assumes you already have an animation constantly playing for the holding of the weapon.

It may look weird that only your arms are moving when you are looking up and down, so you could do the same thing I did for the left and right shoulder joints to the upper torso. You probably don’t want the upper torso to move as much as the arms do when looking around though, so you can divide the math.asin(…) by some number like 2 or 3 to make it react less to the movement of the camera.

local runServ = game:GetService("RunService")

local plr = game.Players.LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()

runServ.RenderStepped:Connect(function()

    char:WaitForChild("RightUpperArm").RightShoulder.C1 = CFrame.new(char.RightUpperArm.RightShoulder.C1.Position) * CFrame.Angles(math.asin(-workspace.CurrentCamera.CFrame.LookVector.Y), 0, 0)

    char:WaitForChild("LeftUpperArm").LeftShoulder.C1 = CFrame.new(char.LeftUpperArm.LeftShoulder.C1.Position) * CFrame.Angles(math.asin(-workspace.CurrentCamera.CFrame.LookVector.Y), 0, 0)

    char:WaitForChild("UpperTorso").Waist.C1 = CFrame.new(char.UpperTorso.Waist.C1.Position) * CFrame.Angles(math.asin(-workspace.CurrentCamera.CFrame.LookVector.Y)/2, 0, 0)

end)

If you do decide to do that, you would also need to change how affected the arms are by the rotation of the camera as now you have the CFrame rotation of the arms and the the CFrame rotation of the torso which effects the arms as well. This would mean that if you were to test it now without dividing the previous math.asin(…) values you found for the arms, the arms would rotate farther than they would be able to naturally, and it would look fairly weird.

Because of this, it would be wise to divide those values as well, giving us our final script:

local runServ = game:GetService("RunService")

local plr = game.Players.LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()

runServ.RenderStepped:Connect(function()

    char:WaitForChild("RightUpperArm").RightShoulder.C1 = CFrame.new(char.RightUpperArm.RightShoulder.C1.Position) * CFrame.Angles(math.asin(-workspace.CurrentCamera.CFrame.LookVector.Y)/2, 0, 0)

    char:WaitForChild("LeftUpperArm").LeftShoulder.C1 = CFrame.new(char.LeftUpperArm.LeftShoulder.C1.Position) * CFrame.Angles(math.asin(-workspace.CurrentCamera.CFrame.LookVector.Y)/2, 0, 0)

    char:WaitForChild("UpperTorso").Waist.C1 = CFrame.new(char.UpperTorso.Waist.C1.Position) * CFrame.Angles(math.asin(-workspace.CurrentCamera.CFrame.LookVector.Y)/2, 0, 0)

end)

Wow! Incredible explanation, I really appreciate it. However, the result is not completely as expected. This might be because of animation overrides or so, but the torso results are fine, while the arms seem to be moving pretty weird.

Still, after messing around in another baseplate it works, although the limbs don’t exactly face away from the camera:

The first problem is a very particular issue that I had a long time ago and forgot to mention. In the ‘workspace’ object in studio, set the value of ‘Retargetting’ from default to disabled:
image

The second problem you brought up with the limbs not exactly facing away from the camera is due to the rotation of the torso and the arms together. I divided the math.asin(…) value for the arms by 2 as to account for the over rotation, but dividing by 2 was more of a rough estimate. I can’t think of what math you would need to do to think of how much you should be dividing the arms by to get them perfectly facing the camera, but you could just mess around with the dividing value of 2 by increasing or decreasing it incrementally until the arms rotate in what seems to be a realistic fashion.

1 Like

Thank you so much for the help! Dividing the value by -1.5 worked perfectly for me!

1 Like

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