Need help with smooth camera switching over shoulder

hey so I have this over the shoulder cam system I made with the help of youtube a while back and I want to be able to switch shoulders smoothly and make it not look like it’s just teleporting into the other shoulder position, some parts of the script aren’t used as I don’t like them for my system but they are still in there, there should also be some notes that help me guide my script so they might help you too, any help is appreciated.

Example of what i want, a smooth tween looking thing:
https://gyazo.com/e045c1a68714691b4b89930ff985f0b0

Script:

local players = game:GetService("Players")
local contextactionservece = game:GetService("ContextActionService")
local RunService = game:GetService("RunService")
local UserInput = game:GetService("UserInputService")
local TweenServ = game:GetService("TweenService")
--------
local Camera = workspace.CurrentCamera
local player = game.Players.LocalPlayer
local cameraOffset = Vector3.new(1.5, 2, 12)
local OGcameraOffset = Vector3.new(1.5, 2, 12)
local cameraOffset2 = Vector3.new(-1.5, 2, 12)
local isRight = true
-----------------------------------------------------------------------
player.CharacterAdded:Connect(function(character)
	-- actual camera function, i.e positioning
	
	local humanoid = character:WaitForChild("Humanoid")
	local rootPart = character:WaitForChild("HumanoidRootPart")
	
	local cameraAngleX = 0
	local cameraAngleY = 0
	
	
	
	local function playerInput (actionName, inputState, inputObject)
		if inputState == Enum.UserInputState.Change then
			
			cameraAngleX -= inputObject.Delta.X
			cameraAngleY = math.clamp(cameraAngleY - inputObject.Delta.Y * 0.4, -75, 75)
			
		end
	end
	
	contextactionservece:BindAction("PlayerInput", playerInput, false, Enum.UserInputType.MouseMovement, Enum.UserInputType.Touch)
	
	RunService:BindToRenderStep("CameraUpdate", Enum.RenderPriority.Camera.Value, function()
		
		local startCFrame = CFrame.new(rootPart.CFrame.Position) * CFrame.Angles(0, math.rad(cameraAngleX), 0) * CFrame.Angles(math.rad(cameraAngleY), 0, 0)
		local cameraCFrame = startCFrame:PointToWorldSpace(cameraOffset)
		local cameraFocus = startCFrame:PointToWorldSpace(Vector3.new(cameraOffset.X, cameraOffset.Y, -1000000))
	
		-- sensitivity
		
		UserInput.MouseDeltaSensitivity = 0.5
		
		--
		Camera.CFrame = CFrame.lookAt(cameraCFrame, cameraFocus)
		-- shift lock
		
		--local lookingCFrame = CFrame.lookAt(rootPart.Position, Camera.CFrame:PointToWorldSpace(Vector3.new(0, 0, -1000000)))
		--rootPart.CFrame = CFrame.fromMatrix(rootPart.Position, lookingCFrame.XVector, rootPart.CFrame.YVector)
		--humanoid.AutoRotate = false 
		--
		-- clipping
		local Character = game.Players.LocalPlayer.Character
		local CameraRay = Ray.new(Character.Head.Position, Camera.CFrame.Position - Character.Head.Position)
		local Ignore = {Character}

		local HitPart, HitPosition = game.Workspace:FindPartOnRayWithIgnoreList(CameraRay, Ignore)

		Camera.CFrame = (Camera.CFrame - (Camera.CFrame.Position - HitPosition)) + (Character.Head.Position - Camera.CFrame.Position).Unit
		--
		
	end)
	
end) 
------------------------------------------------------------------------
local function focusControl(actionName, inputState, inputObject)
	--mouse control / locking center
		
		Camera.CameraType = Enum.CameraType.Scriptable
		
		UserInput.MouseBehavior = Enum.MouseBehavior.LockCenter
		--UserInput.MouseIconEnabled = false   //MAKE MOUSE GO ICON GO POOF
		
		contextactionservece:UnbindAction("FocusControl")
	
end

contextactionservece:BindAction("FocusControl", focusControl, false, Enum.UserInputType.MouseButton1, Enum.UserInputType.Touch, Enum.UserInputType.Focus)
-- change shoulder ---------------------------------------
local function inputBegan(input, gameProcessedEvent)
	if input.UserInputType == Enum.UserInputType.Keyboard then
		if input.KeyCode == Enum.KeyCode.T then
			if not gameProcessedEvent then
			if isRight == true then
					cameraOffset = cameraOffset2
					isRight = false
				else
					cameraOffset = OGcameraOffset
					isRight = true
				end
			end
		end
	end
end
UserInput.InputBegan:Connect(inputBegan)

Instead of setting the camera’s CFrame you should use CFrame:lerp() and lerp it smoothly.

hey so i tried to but it does nothing so think you know what could be wrong?

Script:

local function inputBegan(input, gameProcessedEvent)
	if input.UserInputType == Enum.UserInputType.Keyboard then
		if input.KeyCode == Enum.KeyCode.T then
			if not gameProcessedEvent then
				if isRight == true then
					for i = 0,1, .01 do
						wait()
						Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(-1.5, 2, 12), i)
					end
					isRight = false
				else
					for i = 0,1, .01 do
						wait()
						Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(1.5, 2, 12), i)
					end
					isRight = true
				end
			end
		end
	end
end
UserInput.InputBegan:Connect(inputBegan)

make Camera.CFrame a variable and do the for loop after
Camera.CFrame = cameraCFrame:Lerp(CFrame.new(-1.5, 2, 12), i)

i did this and it didn’t work, mind telling me what i did wrong?

Script:

local function inputBegan(input, gameProcessedEvent)
	if input.UserInputType == Enum.UserInputType.Keyboard then
		if input.KeyCode == Enum.KeyCode.T then
			if not gameProcessedEvent then
				if isRight == true then
					local cameraCframe = Camera.CFrame
					for i = 0,1, .01 do
						wait()
						Camera.CFrame = cameraCframe:Lerp(CFrame.new(-1.5, 2, 12), i)
					end
					isRight = false
				else
					local cameraCframe = Camera.CFrame
					for i = 0,1, .01 do
						wait()
						Camera.CFrame = cameraCframe:Lerp(CFrame.new(1.5, 2, 12), i)
					end
					isRight = true
				end
			end
		end
	end
end
UserInput.InputBegan:Connect(inputBegan)

Camera variable is: local Camera = workspace.CurrentCamera
also this is in a local script which is located in StarterPlayerScripts

are you sure that part of the code is running (for ex. isRight var), I ran the same exact code and it worked.

ill do some test and get back to you but i wanna say, i don’t have a part spawned and grouped to the player at all times i just move the cam to the location, do you think that could cause a problem?

yeah the code seems to be running and it still won’t work, it also makes the player jitter a little when they turn and the code has ran but after a bit that fixes it self, ill find a way to do this then update this post

What you’re currently attempting is lerping the camera’s CFrame to those coordinates in world space. This is already being overridden by another section of your script, which is why it appears to jitter (it’s moving to that location and then being pulled back).

What you really need to do is lerp the Vector3 value you’re using for the offset, not the camera’s CFrame. You can use something like cameraOffset = cameraOffset:Lerp(cameraOffset2, i) for this.

Another thing to note is that when using wait() in your for loop, you’re locking the transition to 30FPS at best. There’s a longer explanation for that solution, but I just thought I’d at least note that here.

2 Likes

it worked but the jittering is a problem, i think it is happening because i have a RunService running to make the camera stay in that position but i don’t know how i would make it not jitter without breaking the entire cam system, have any ideas?

Can you explain what you mean by “jittering”? A video would be best, if possible.

1 Like

never mind I fixed this by adding a cooldown to the change camera option so players could not spam the button, the problem was when I spammed my change camera button it changed it to the left shoulder then back to the right thus making it fight itself, I fixed it with a one-second cooldown, thank you for all your help.

1 Like