How to stop custom camera swapping script breaking with third person?

Hello! What I am trying to do with this script is make a system which allows the player to switch from first person to third person, and then let the player lock the mouse to the middle of the screen. This is all working but for some reason. When you are in “ThirdPerson” camera mode (which is the one without the shift lock mechanic), you cannot move the camera using right click. Sometimes you can only nudge it maybe a few degrees for a frame or two but otherwise it wont let you move your camera by holding the right mouse button like you usually can in third person in roblox. All help is appreciated ^^

local ContextActionUtility = require(game:GetService('ReplicatedStorage'):WaitForChild("ContextActionUtility"))
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local playerSettings = player.PlayerScripts:WaitForChild('PlayerSettings')
local camera = workspace.CurrentCamera

local UIS = game:GetService("UserInputService")

local runService = game:GetService('RunService')
local currentMode = "FirstPerson"
playerSettings:SetAttribute("CameraMode", "FirstPerson")

local CAMERA_LOCK_SMOOTHNESS = 8
local CAMERA_LOCK_OFFSET = Vector3.new(1.75, 1.75, 0)

local yaw = 0
local pitch = 0

local SENSITIVITY = 0.25
local MIN_PITCH = -75
local MAX_PITCH = 75

local character, root, humanoid, head

local function setupCharacter(char)
	character = char
	root = char:WaitForChild("HumanoidRootPart")
	humanoid = char:WaitForChild("Humanoid")
	head = char:WaitForChild("Head")
end

if player.Character then
	setupCharacter(player.Character)
end
player.CharacterAdded:Connect(setupCharacter)

local smoothPos = camera.CFrame.Position

local function CameraToggle(actionName, inputState, inputObject)
	if inputState == Enum.UserInputState.Begin then
		if currentMode == "FirstPerson" then
			print("3rd")
			currentMode = "ThirdPerson"
			playerSettings:SetAttribute("CameraMode", "ThirdPerson")
		else
			print("1st")
			currentMode = "FirstPerson"
			playerSettings:SetAttribute("CameraMode", "FirstPerson")
		end
	end	
end

local function ToggleLock(actionName, inputState, inputObject)
	if inputState == Enum.UserInputState.Begin then
		if currentMode == "FirstPerson" then return end
		if currentMode == "ThirdPerson" then
			currentMode = "ThirdPersonLock"
			playerSettings:SetAttribute("CameraMode", "ThirdPersonLock")
		elseif currentMode == "ThirdPersonLock" then 
			currentMode = "ThirdPerson"
			playerSettings:SetAttribute("CameraMode", "ThirdPerson")
		end
	end
end

runService.RenderStepped:Connect(function(dt)
	if currentMode == "FirstPerson" then
		player.CameraMode = Enum.CameraMode.LockFirstPerson
		player.CameraMinZoomDistance = 0.5
		player.CameraMaxZoomDistance = 0.5
		UIS.MouseBehavior = Enum.MouseBehavior.LockCenter
		humanoid.CameraOffset = Vector3.new(0,0,-0.9)
		for _, v in character:GetChildren() do
			if (v:IsA("BasePart") and v ~= head) then
				v.LocalTransparencyModifier = 0
			end
			if v:IsA("Accessory") and not (v.AccessoryType == Enum.AccessoryType.Hair or v.AccessoryType == Enum.AccessoryType.Hat or v.AccessoryType == Enum.AccessoryType.Face) then
				v:FindFirstChild('Handle').LocalTransparencyModifier = 0
			end
		end
	elseif currentMode == "ThirdPerson" then
		humanoid.CameraOffset = Vector3.new()
		player.CameraMode = Enum.CameraMode.Classic
		player.CameraMinZoomDistance = 6
		player.CameraMaxZoomDistance = 12
		UIS.MouseBehavior = Enum.MouseBehavior.Default
	elseif currentMode == "ThirdPersonLock" then
		local lookVector = camera.CFrame.LookVector
		local zoom = math.clamp((camera.CFrame.Position - root.Position).Magnitude, 6, 12) 
		local cameraPos = root.Position - lookVector * zoom + root.CFrame.RightVector * CAMERA_LOCK_OFFSET.X + root.CFrame.UpVector * CAMERA_LOCK_OFFSET.Y
		local alpha = 1 - math.exp(-CAMERA_LOCK_SMOOTHNESS * dt)
		smoothPos = smoothPos:Lerp(cameraPos, alpha)
		local newCFrame = CFrame.new(smoothPos) * (camera.CFrame - camera.CFrame.Position)
		camera.CFrame = newCFrame
		UIS.MouseBehavior = Enum.MouseBehavior.LockCenter
	end
end)	

ContextActionUtility:BindActionAtPriority("Camera Toggle", CameraToggle, true, 3, Enum.KeyCode.V)
--ContextActionUtility:SetImage("Camera Toggle", "rbxassetid://111292680671790") -- need an iamge	
ContextActionUtility:BindActionAtPriority("Toggle Lock", ToggleLock, true, 4, Enum.KeyCode.LeftControl, Enum.KeyCode.RightControl)
--ContextActionUtility:SetImage("Camera Toggle", "rbxassetid://111292680671790") -- need an iamge	
1 Like

Hello. I’ve tested your script and my best guess would be because when you hold your right mouse button, the camera automatically switches your mouse behavior to Enum.MouseBehavior.LockCurrentPosition. In your loop, you’re actively setting it to Default every frame. When you hold the right mouse button, it goes back immediately to the Default state which causes the problem.

Try removing this and then you will notice it will allow you to move your camera now

humanoid.CameraOffset = Vector3.new()
		player.CameraMode = Enum.CameraMode.Classic
		player.CameraMinZoomDistance = 6
		player.CameraMaxZoomDistance = 12
		UIS.MouseBehavior = Enum.MouseBehavior.Default < -- THIS
3 Likes

Adding to this, instead of running this every frame, you can use

Instance:GetAttributeChangedSingal(“AttributeName”):Connect(function()

end)

This not only fixes the issue of your camera mode being set to Default when attempting to rotate, it’s also more performant.

*sorry for any mistakes I’m on my phone at the moment

3 Likes

oh I understand now. I ended up making it so it will only change the mouse mode if the mode last tick/frame is different than the current mode and it now works. Thank you ^^

local lastMode = nil

runService.RenderStepped:Connect(function(dt)
	if currentMode == "FirstPerson" then
		player.CameraMode = Enum.CameraMode.LockFirstPerson
		player.CameraMinZoomDistance = 0.5
		player.CameraMaxZoomDistance = 0.5
		UIS.MouseBehavior = Enum.MouseBehavior.LockCenter
		humanoid.CameraOffset = Vector3.new(0,0,-0.9)
		for _, v in character:GetChildren() do
			if (v:IsA("BasePart") and v ~= head) then
				v.LocalTransparencyModifier = 0
			end
			if v:IsA("Accessory") and not (v.AccessoryType == Enum.AccessoryType.Hair or v.AccessoryType == Enum.AccessoryType.Hat or v.AccessoryType == Enum.AccessoryType.Face) then
				v:FindFirstChild('Handle').LocalTransparencyModifier = 0
			end
		end
	elseif currentMode == "ThirdPerson" then
		humanoid.CameraOffset = Vector3.new()
		player.CameraMode = Enum.CameraMode.Classic
		player.CameraMinZoomDistance = 6
		player.CameraMaxZoomDistance = 12
		if lastMode ~= currentMode then
			UIS.MouseBehavior = Enum.MouseBehavior.Default
		end
	elseif currentMode == "ThirdPersonLock" then
		local lookVector = camera.CFrame.LookVector
		local zoom = math.clamp((camera.CFrame.Position - root.Position).Magnitude, 6, 12) 
		local cameraPos = root.Position - lookVector * zoom + root.CFrame.RightVector * CAMERA_LOCK_OFFSET.X + root.CFrame.UpVector * CAMERA_LOCK_OFFSET.Y
		local alpha = 1 - math.exp(-CAMERA_LOCK_SMOOTHNESS * dt)
		smoothPos = smoothPos:Lerp(cameraPos, alpha)
		local newCFrame = CFrame.new(smoothPos) * (camera.CFrame - camera.CFrame.Position)
		camera.CFrame = newCFrame
		UIS.MouseBehavior = Enum.MouseBehavior.LockCenter
	end
	lastMode = currentMode
end)	
3 Likes