How to Manipulate the Camera for 3rd Person Games(3rd Person Camera)

Introduction

Having a 3rd person camera is really useful when making a 3rd person game such as a 3rd person shooter game. In this tutorial I will be giving step by step instructions to help you achieve the perfect 3rd person camera system. Without further ado lets get into this tutorial.

Step 1:

First we create the one and only script we need which is a local script which will be located in StarterGUI
image

Coding Time

Step 2:

Let’s start off by defining a few game services and variables.

--|| SERVICES ||--
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
--|| VARIABLES ||--
local Camera = workspace.Camera
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
local CameraAngleX, CameraAngleY = 0,0
local CameraCFrame,CameraFocus,StartCFrame
local Movement = Enum.UserInputType.MouseMovement
--|| SETTINGS ||--
local CameraOffset = Vector3.new(1,3,9.5)  -- Offset of the Camera, Change this to whatever you like.

Now that we have defined our variables we can move on the main part. We start off by creating a RenderStepped loop. Then setting the CameraType of the local player to Scriptable if it isn’t already on scriptable. Then we set StartCFrame to the HumanoidRootPart CFrame.Position then multiplying it by CFrame.Angles(0, math.rad(CameraAngleX), 0) and CFrame.Angles(math.rad(CameraAngleY), 0, 0)

RunService.RenderStepped:Connect(function()
	if Camera.CameraType ~= Enum.CameraType.Scriptable then
		Camera.CameraType = Enum.CameraType.Scriptable
	end
	StartCFrame = CFrame.new((HumanoidRootPart.CFrame.Position)) * CFrame.Angles(0, math.rad(CameraAngleX), 0) *  CFrame.Angles(math.rad(CameraAngleY), 0, 0)
end)

Now we set CameraCFrame to StartCFrame:ToWorldSpace with CFrame.new(CameraOffset x y and z).

RunService.RenderStepped:Connect(function()
	if Camera.CameraType ~= Enum.CameraType.Scriptable then
		Camera.CameraType = Enum.CameraType.Scriptable
	end
	StartCFrame = CFrame.new((HumanoidRootPart.CFrame.Position)) * CFrame.Angles(0, math.rad(CameraAngleX), 0) *  CFrame.Angles(math.rad(CameraAngleY), 0, 0)
	CameraCFrame = StartCFrame:ToWorldSpace(CFrame.new(CameraOffset.X, CameraOffset.Y, CameraOffset.Z))
end)

We now set the CameraFocus as the same as CameraCFrame except the Z axis is -10000. Now we can set the Camera CFrame to CFrame.new(CameraCFrame.Position, CameraFocus.Position). This will make our Camera move relative to the HumanoidRootPart Position. If we want our Character to also rotate whiles we are looking around we can also change its CFrame based on the CameraAngleX.

With HumanoidRootPart Rotation - https://gyazo.com/414b5ccd17a4d5ddcbd281e0e65ef334

Without HumanoidRootPart Rotation - https://gyazo.com/5d1a5d42f01ccc45a420b6a98a8e951e

RunService.RenderStepped:Connect(function()
	if Camera.CameraType ~= Enum.CameraType.Scriptable then
		Camera.CameraType = Enum.CameraType.Scriptable
	end
	StartCFrame = CFrame.new((HumanoidRootPart.CFrame.Position)) * CFrame.Angles(0, math.rad(CameraAngleX), 0) *  CFrame.Angles(math.rad(CameraAngleY), 0, 0)
	CameraCFrame = StartCFrame:ToWorldSpace(CFrame.new(CameraOffset.X, CameraOffset.Y, CameraOffset.Z))
	CameraFocus = StartCFrame:ToWorldSpace(CFrame.new(CameraOffset.X, CameraOffset.Y, -10000))
	Camera.CFrame = CFrame.new(CameraCFrame.Position, CameraFocus.Position)
	
	
	--|| Rotating the Character with mouse ||--
	HumanoidRootPart.CFrame = CFrame.new(HumanoidRootPart.Position) * CFrame.Angles(0, math.rad(CameraAngleX), 0)
end)

Now lets move on to UserInputService. We first create a InputBegan event then check if the MouseBehavior is Locked to the center.

UserInputService.InputBegan:Connect(function(InputObject)
	local UserInputType = InputObject.UserInputType
	if UserInputService.MouseBehavior ~= Enum.MouseBehavior.LockCenter then
		UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
	end
end)

Now we add a InputChanged event which will be used to change CameraAngle X and CameraAngleY based on the Delta of the InputObject returned. We also have to check if the UserInputType is Enum.UserInputType.MouseMovement so the CameraAngle X and Y are only changed when MouseMovement is changed.

UserInputService.InputChanged:Connect(function(InputOject)
	local UserInputType= InputOject.UserInputType
	if(UserInputType== Movement)then
		local Delta = InputOject.Delta
		CameraAngleX = CameraAngleX-Delta.X
		CameraAngleY = math.clamp(CameraAngleY-Delta.Y, -75, 75)
	end
end)

Now that we are done our whole script should look something similar to this. And should have a end result of something similar to this. https://gyazo.com/088854d9a31f2ffa1651237379f33cb2

--|| SERVICES ||--
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
--|| VARIABLES ||--
local Camera = workspace.Camera
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
local CameraAngleX, CameraAngleY = 0,0
local CameraCFrame,CameraFocus,StartCFrame
local CameraOffset = Vector3.new(1,3,9.5)
local Movement = Enum.UserInputType.MouseMovement
RunService.RenderStepped:Connect(function()
	if Camera.CameraType ~= Enum.CameraType.Scriptable then
		Camera.CameraType = Enum.CameraType.Scriptable
	end
	StartCFrame = CFrame.new((HumanoidRootPart.CFrame.Position)) * CFrame.Angles(0, math.rad(CameraAngleX), 0) *  CFrame.Angles(math.rad(CameraAngleY), 0, 0)
	CameraCFrame = StartCFrame:ToWorldSpace(CFrame.new(CameraOffset.X, CameraOffset.Y, CameraOffset.Z))
	CameraFocus = StartCFrame:ToWorldSpace(CFrame.new(CameraOffset.X, CameraOffset.Y, -10000))
	Camera.CFrame = CFrame.new(CameraCFrame.Position, CameraFocus.Position)
	
	
	--|| Rotating the Character with mouse ||--
	--HumanoidRootPart.CFrame = CFrame.new(HumanoidRootPart.Position) * CFrame.Angles(0, math.rad(CameraAngleX), 0)
end)
UserInputService.InputBegan:Connect(function(InputObject)
	local UserInputType = InputObject.UserInputType
	if UserInputService.MouseBehavior ~= Enum.MouseBehavior.LockCenter then
		UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
	end
end)
UserInputService.InputChanged:Connect(function(InputOject)
	local UserInputType= InputOject.UserInputType
	if(UserInputType== Movement)then
		local Delta = InputOject.Delta
		CameraAngleX = CameraAngleX-Delta.X
		CameraAngleY = math.clamp(CameraAngleY-Delta.Y, -75, 75)
	end
end)

Conclusion

That will be it for this tutorial.

Downloads

Full Downloadable Working DEMO: 3rd Person Camera Tutorial.rbxl (22.4 KB)

18 Likes

thanks this really helped, but could you make a tatorial on how to make first person camera?

1 Like

Sure. I will be glad to. But I am not sure what you really mean since you can set the Max and Min Camera Distance to 0?

1 Like

how can you set the camra dis to 0???

1 Like

There is 2 properties in StarterPlayer, CameraMaxZoomDistance and CameraMinZoomDistance, set both of them to 0.5 and your player should be stuck in first person.

1 Like

those two are not in starterplayer though

You can set the the players CameraMode to LockFirstPerson.
[player].CameraMode = Enum.CameraMode.LockFirstPerson

@6z3cho Great tutorial, btw :smiley:

1 Like

Yes. You can do what @TheDCraft , that will also work. Also here are the properties I was talking about. https://gyazo.com/3aed7424f10d16162183c1ea550f33da . And thank you @TheDCraft

This is a great tutorial, except how would I make it so the camera cannot go through objects?