Creating first person-third person toggle camera

I want to create a camera that toggles between first and third person with a key press. The third person camera should be an over the shoulder style camera, while first person is as normal.

--// Lock first person
Player.CameraMode = Enum.CameraMode.LockFirstPerson
Player:SetAttribute("FirstPerson", true)

local function SwapCamera()
	local FirstPerson = Player:GetAttribute("FirstPerson")
	
	if FirstPerson then
		Player.CameraMode = Enum.CameraMode.Classic
		
		UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
		
		local cameraAngleX = 0
		local cameraAngleY = 0

		local function focusControl(actionName, inputState, inputObject)
			-- Lock and hide mouse icon on input began
			if inputState == Enum.UserInputState.Begin then
				UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
				UserInputService.MouseIconEnabled = false
				ContextActionService:UnbindAction("FocusControl", focusControl, false, Enum.UserInputType.MouseButton1, Enum.UserInputType.Touch, Enum.UserInputType.Focus)
			end
		end
		local function playerInput(actionName, inputState, inputObject)
			-- Calculate camera/player rotation on input change
			if inputState == Enum.UserInputState.Change then
				cameraAngleX = cameraAngleX - inputObject.Delta.X
				-- Reduce vertical mouse/touch sensitivity and clamp vertical axis
				cameraAngleY = math.clamp(cameraAngleY-inputObject.Delta.Y*0.4, -75, 75)
				-- Rotate root part CFrame by X delta
				HumanoidRootPart.CFrame = HumanoidRootPart.CFrame * CFrame.Angles(0, math.rad(-inputObject.Delta.X), 0)
			end
		end
		ContextActionService:BindAction("PlayerInput", playerInput, false, Enum.UserInputType.MouseMovement, Enum.UserInputType.Touch)
		
		ContextActionService:BindAction("FocusControl", focusControl, false, Enum.UserInputType.MouseButton1, Enum.UserInputType.Touch, Enum.UserInputType.Focus)

		Render = RunService.RenderStepped:Connect(function()
			local startCFrame = CFrame.new((HumanoidRootPart.CFrame.Position)) * CFrame.Angles(0, math.rad(cameraAngleX), 0) * CFrame.Angles(math.rad(cameraAngleY), 0, 0)
			local cameraCFrame = startCFrame:ToWorldSpace(CFrame.new(CameraOffset.X, CameraOffset.Y, CameraOffset.Z))
			local cameraFocus = startCFrame:ToWorldSpace(CFrame.new(CameraOffset.X, CameraOffset.Y, -10000))
			Camera.CFrame = CFrame.new(cameraCFrame.Position, cameraFocus.Position)
		end)
		
		Player:SetAttribute("FirstPerson", false)
	else -- Make first person
		if Render then
			Render:Disconnect()
		end
		
		UserInputService.MouseBehavior = Enum.MouseBehavior.Default
		
		Player.CameraMode = Enum.CameraMode.LockFirstPerson
		Player:SetAttribute("FirstPerson", true)
	end
end



UserInputService.InputBegan:Connect(function(input, GPE)
	if GPE then return end
	
	if input.KeyCode == Enum.KeyCode.E then
		SwapCamera()
	end
end)

This is third person


Character is invisible, and I can zoom in/out to make visible, but camera is stuck in a pos, mouse is visible, and camera doesnt rotate to always be over player

5 Likes

The reason why your character appears invisible until you zoom out is because you need to lock/set the camera min/max distance. Doing so will disable the player from zooming locking the camera offset and the character will always appear.

Player.CameraMinZoomDistance = 8
Player.CameraMaxZoomDistance = 8

I suggest that you set the CFrame of the humanoid rootpart during the runservice instead of when playerInput is called. I removed the rootPart CFrame update code from playerInput and put it in Render as so:

Render = RunService.RenderStepped:Connect(function()
			local startCFrame = CFrame.new((HumanoidRootPart.CFrame.Position)) * CFrame.Angles(0, math.rad(cameraAngleX), 0) * CFrame.Angles(math.rad(cameraAngleY), 0, 0)
			local cameraCFrame = startCFrame:ToWorldSpace(CFrame.new(CameraOffset.X, CameraOffset.Y, CameraOffset.Z))
			local cameraFocus = startCFrame:ToWorldSpace(CFrame.new(CameraOffset.X, CameraOffset.Y, -10000))
			Camera.CFrame = CFrame.new(cameraCFrame.Position, cameraFocus.Position)
			local lookingCFrame = CFrame.lookAt(HumanoidRootPart.Position, Camera.CFrame:PointToWorldSpace(Vector3.new(0,0,-100000)))
			HumanoidRootPart.CFrame = CFrame.fromMatrix(HumanoidRootPart.Position, lookingCFrame.XVector, HumanoidRootPart.CFrame.YVector)
		end)

I am also making a similar camera system as you and have posted a thread with my code linked below. Feel free to reference it if any other issues come up!
First-Third Person Camera System