Where to start with making a shoulder cam

How can I go about making a shoulder cam similar to shift lock when a player holds a tool?

Any help appreciated!

Simply make it so when the tool is equipped the Camera has an Offset

Something like:

tool.Equipped:Connect(function()
local player = game: GetService(“Players”).LocalPlayer
player.iDontRememberWhereTheCameraInstanceIs.Offset.X = Offset
end

Ok, but how would I make it act like shift lock?

Not sure, I’m not a Peogrammer

I just so happened to make a shoulder camera a few weeks ago! It’s fairly simple!

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()

--<< Misc >>--
local Offset = CFrame.new(2.5, 0.7, 0) -- The camera offset
local Connection

Character.ChildAdded:Connect(function(Child)
    if (Child:IsA("Tool")) then
        --<< This child is a tool: tool has been equipped >>--
        if (Connection and Connection.Connected) then Connection:Disconnect() end

        --<< Update humanoid >>--
        Character:WaitForChild("Humanoid").AutoRotate = false
        local Root = Character:WaitForChild("HumanoidRootPart")

        Connection = RunService.RenderStepped:Connect(function(DT)
            --<< Update the camera >>--
            UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter -- Set to center
            local MouseDelta = UserInputService:GetMouseDelta()
            Camera.CFrame = CFrame.lookAt(Camera.CFrame.Position, Camera.CFrame * CFrame.new(MouseDelta.X, -MouseDelta.Y, -20000).Position) *  Offset
            
            --<< Now, update the rootpart >>--
            local RootCFrame = CFrame.lookAt(Root.Position, Camera.CFrame:PointToWorldSpace(Vector3.new(0, 0, -20000)))
            Root.CFrame = CFrame.fromMatrix(Root.Position, RootCFrame.XVector, Root.CFrame.YVector)
        end)
    end            
end)

Character.ChildRemoved:Connect(function(Child)
    --<< This child has been removed >>--
    if (Child:IsA("Tool")) then
        --<< No longer equipped: disconnect the connection >>--
        if (Connection and Connection.Connected) then Connection:Disconnect() end
        
        --<< Update the humanoid again >>--
        UserInputService.MouseBehavior = Enum.MouseBehavior.Default
        Character:WaitForChild("Humanoid").AutoRotate = true
    end
end)

I have not tested this so there may be a few errors I’m not seeing but let me know if you have any questions!

Yea this works, but how can I make it so that if the player presses F then it disconnects the connection?

I have a toggle animation thing, when the player presses F it will toggle the animation and I want it to turn of the connection then, but if the plyer presses F again it will go back to the first animation and I want the shoulder cam to become active again (I want to reconnect the connection).

Gotcha! UserInputService.InputBegan is useful for cases like this.

It can be implemented into the code I sent like so:

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Camera = workspace.CurrentCamera

--<< Misc >>--
local Offset = CFrame.new(2.5, 0.7, 0) -- The camera offset
local Connection
local Current

Character.ChildAdded:Connect(function(Child)
	if (Child:IsA("Tool")) then
		--<< This child is a tool: tool has been equipped >>--
		if (Connection and Connection.Connected) then Connection:Disconnect() end
		
		--<< Toggle on initially >>--
		Character:WaitForChild("Humanoid").AutoRotate = false
		local Root = Character:WaitForChild("HumanoidRootPart")

		Connection = RunService.RenderStepped:Connect(function(DT)
			--<< Update the camera >>--
			UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter -- Set to center
			local MouseDelta = UserInputService:GetMouseDelta()
			Camera.CFrame = CFrame.lookAt(Camera.CFrame.Position, Camera.CFrame * CFrame.new(MouseDelta.X, -MouseDelta.Y, -20000).Position) *  Offset

			--<< Now, update the rootpart >>--
			local RootCFrame = CFrame.lookAt(Root.Position, Camera.CFrame:PointToWorldSpace(Vector3.new(0, 0, -20000)))
			Root.CFrame = CFrame.fromMatrix(Root.Position, RootCFrame.XVector, Root.CFrame.YVector)
		end)
		
		Current = Child -- Update the current tool
	end            
end)

Character.ChildRemoved:Connect(function(Child)
	--<< This child has been removed >>--
	if (Child:IsA("Tool")) then
		--<< No longer equipped: disconnect the connection >>--
		if (Connection and Connection.Connected) then Connection:Disconnect() end
		Current = nil -- There is no longer a current tool

		--<< Update the humanoid again >>--
		UserInputService.MouseBehavior = Enum.MouseBehavior.Default
		Character:WaitForChild("Humanoid").AutoRotate = true
	end
end)

UserInputService.InputBegan:Connect(function(Input, Processed)
	if (Processed) then return end -- Probably typing?
	
	if (Input.KeyCode == Enum.KeyCode.F) then
		--<< F has been pressed >>--
		if (Connection and Connection.Connected) then
			--<< Toggle off >>--
			Connection:Disconnect()
			UserInputService.MouseBehavior = Enum.MouseBehavior.Default
			Character:WaitForChild("Humanoid").AutoRotate = true
		elseif (Current ~= nil) then -- Assuming you want this to only be togglable if a tool is equipped
			--<< Toggle on >>--
			Character:WaitForChild("Humanoid").AutoRotate = false
			local Root = Character:WaitForChild("HumanoidRootPart")

			Connection = RunService.RenderStepped:Connect(function(DT)
				--<< Update the camera >>--
				UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter -- Set to center
				local MouseDelta = UserInputService:GetMouseDelta()
				Camera.CFrame = CFrame.lookAt(Camera.CFrame.Position, Camera.CFrame * CFrame.new(MouseDelta.X, -MouseDelta.Y, -20000).Position) *  Offset

				--<< Now, update the rootpart >>--
				local RootCFrame = CFrame.lookAt(Root.Position, Camera.CFrame:PointToWorldSpace(Vector3.new(0, 0, -20000)))
				Root.CFrame = CFrame.fromMatrix(Root.Position, RootCFrame.XVector, Root.CFrame.YVector)
			end)
		end
	end
end)

I tested this and it did work on my end but let me know if you have any problems!

UIS.InputBegan:Connect(function(input, IsTyping)
	if IsTyping then return end
	if Equipped then
		if input.KeyCode == Enum.KeyCode.F and isShooting == false then
			isShooting = true
			PatrolAnim:Stop()
			ShootAnim:Play()
			-- connection should be connected here
		elseif input.KeyCode == Enum.KeyCode.F and isShooting == true then
			isShooting = false
			PatrolAnim:Play()
			ShootAnim:Stop()
			-- connection should be disconnected here
      end
	end
end)

This is my code for pressing F to toggle the animations while the player is holding the tool.

UIS.InputBegan:Connect(function(input, IsTyping)
	if IsTyping then return end
	if Equipped then
		if input.KeyCode == Enum.KeyCode.F and isShooting == false then
			isShooting = true
			-- connection should be connected here
			if Connection and Connection.Connected then Connection:Disconnect() end
			Character:WaitForChild("Humanoid").AutoRotate = false
			local Root = Character:WaitForChild("HumanoidRootPart")

			Connection = RunService.RenderStepped:Connect(function(DT)
				--<< Update the camera >>--
				UIS.MouseBehavior = Enum.MouseBehavior.LockCenter -- Set to center
				local MouseDelta = UIS:GetMouseDelta()
				Camera.CFrame = CFrame.lookAt(Camera.CFrame.Position, Camera.CFrame * CFrame.new(MouseDelta.X, -MouseDelta.Y, -20000).Position) *  Offset

				--<< Now, update the rootpart >>--
				local RootCFrame = CFrame.lookAt(Root.Position, Camera.CFrame:PointToWorldSpace(Vector3.new(0, 0, -20000)))
				Root.CFrame = CFrame.fromMatrix(Root.Position, RootCFrame.XVector, Root.CFrame.YVector)
			end)
		elseif input.KeyCode == Enum.KeyCode.F and isShooting == true then
			isShooting = false
			-- connection should be disconnected here
			if Connection and Connection.Connected then Connection:Disconnect() end
			UIS.MouseBehavior = Enum.MouseBehavior.Default
			Character:WaitForChild("Humanoid").AutoRotate = true
		end
	end
end)

The thing is, I want the connection to be connected when the player holds the tool and also if the shootAnim animation is playing, but I want the connection to disconnect if the patrolAnim animation is playing or if the player stops holding the tool.