Weird Camera Offset

Currently, if I equip a tool & the over-the-shoulder camera enables, it flicks to a weird position. How would I be able to fix that?

Are there specific methods that I’m not using? Should I be doing this in a completely different way? All of the other FPS games seem to have a smooth transition/or none between equipping and unequipping a gun, even though there’s a difference. (From the default right click camera movement to purely mouse movement)

Local Script under a handle under a tool.

local Players = game:GetService("Players")
local ContextActionService = game:GetService("ContextActionService")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")

local camera = workspace.CurrentCamera
local cameraOffset = Vector3.new(2, 2, 8)
local player = Players.LocalPlayer

local rootPart
local humanoid
local signal

local tool = script.Parent.Parent

local cameraAngleX = 0
local cameraAngleY = 0
local enabled = false

player.CharacterAdded:Connect(function(character)
	humanoid = character:WaitForChild("Humanoid")
	rootPart = character:WaitForChild("HumanoidRootPart")
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.2, -75, 75)	
	end
end

ContextActionService:BindAction("PlayerInput", playerInput, false, Enum.UserInputType.MouseMovement)

tool.Equipped:Connect(function()	
	humanoid.AutoRotate = false
	
	-- Lock and hide mouse icon on input began
	UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
	UserInputService.MouseIconEnabled = false


	signal = RunService.RenderStepped:Connect(function(deltaTime)
		local startCFrame = CFrame.new((rootPart.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 LookVector = camera.CFrame.LookVector * 10
		local FinalVector = LookVector - Vector3.new(0, LookVector.Y, 0)
		local HumanoidPosition = rootPart.Position

		--Sets humanoid position
		rootPart.CFrame = CFrame.new(HumanoidPosition, HumanoidPosition + FinalVector)

		rootPart.CFrame =
			rootPart.CFrame:Lerp(CFrame.new(HumanoidPosition, HumanoidPosition + FinalVector), 8 * deltaTime)
	end)
	
	enabled = true
end)

tool.Unequipped:Connect(function()
	UserInputService.MouseBehavior = Enum.MouseBehavior.Default
	UserInputService.MouseIconEnabled = true
	signal:Disconnect()
	camera.CameraType = Enum.CameraType.Custom
	humanoid.AutoRotate = true
	enabled = false
end)

Thanks for your help!

Try it in-game, studio sometimes has issues with mouse

I’ve tried both in-game with QA testers AND in studio. Same issue.

Are you using a custom camera by any chance, like switching from scriptable to custom?

I’m using the roblox default camera. It doesn’t change to scriptable when the tool is equipped (I’ve given that a try just now). Should I be using a scriptable camera for the entire game?

I see, your problem may be because the CameraAngleX may be different value, it should change when you hold right click and turn your camera around but you may be using keys to turn the camera around which is why when you re-equip the tool it snaps back to the last X rotation value it has recorded

Oh I see. So I should be measuring the camera CFrame change instead of directly measuring user input?

I’ll take a look for you about this issue

1 Like

Swap the function for this:

local function playerInput(actionName, inputState, inputObject)
	-- Calculate camera/player rotation on input change
	if inputState == Enum.UserInputState.Change then
		cameraAngleX = cameraAngleX - (inputObject.Delta.X / 2)
		cameraAngleY = math.clamp(cameraAngleY-inputObject.Delta.Y*0.2, -75, 75)	
	end	
end

From personal experience on this matter, roblox for some reason gives different Delta between mouse positions in different camera modes. In custom the camera Delta is twice more active why is why when you turn to the right it says the total mousemovement was 180 degrees to the right, however in modes like Scriptable or in any other camera manipulation situation the camera decides to give more accurate estimate of 90 degrees (the correct one), to my knowledge it does the same if in FPS and this issue took me ages to figure out however if you just printed the values of delta you could of gotten there yourself.