Toggling an Over the-shoulder camera

In one of my games I need an over the shoulder camera angle, I’ve attempted many methods but this seems to be the closest I’ve gotten.

On the Roblox developer site there is a section called Camera Manipulation, with a sample for an Over-The-Shoulder camera, so I decided to edit it in an attempt to make it togglable.

What I tried to do what set it so that it would only set the camera to Scriptable and setup the other components for the Frame stuff if a Boolean was set to true, and then if set to false it would set the camera type to Custom once again.

Instead what happens is the camera upon starting the game will stay in a position (Im assuming 0,0,0) until the boolean is activated, then will go to where the player is in the proper spot, however it will not follow. As well as this, when the boolean is set to false it doesn’t result in anything happening.

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 saberAssets = game.ReplicatedStorage.SaberAssets
 
player.CharacterAdded:Connect(function(character)
 
	local humanoid = character:WaitForChild("Humanoid")
	local rootPart = character:WaitForChild("HumanoidRootPart")
	
 
	 
	saberAssets.Ignited.Changed:Connect(function()
		
		
		if saberAssets.Ignited.Value == true then
			local cameraAngleX = 0
			local cameraAngleY = 0
			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
			rootPart.CFrame = rootPart.CFrame * CFrame.Angles(0, math.rad(-inputObject.Delta.X), 0)
		end
	end
	ContextActionService:BindAction("PlayerInput", playerInput, false, Enum.UserInputType.MouseMovement, Enum.UserInputType.Touch)

			
			camera.CameraType = Enum.CameraType.Scriptable
			humanoid.AutoRotate = false
 
		
			UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
			UserInputService.MouseIconEnabled = false
		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)
		else
			camera.CameraType = Enum.CameraType.Custom
		end
	end)
end)
 
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

2 Likes

Have you tried:

  1. Setting Camera.CameraSubject to the Client’s humanoid or humanoidrootpart when the OTS camera is off?
  2. Changing the Camera.CameraType back to its default setting when the OTS camera is off?

Alternatively, here is the post to a OTS camera that I made a few months ago: Just add Un/BindFromRenderStep and it should be fine in your case.

1 Like

For the camera position to update every frame you’d need to use RenderStepped in a local script. Alternatively, you could manipulate the Humanoid Camera Offset.

https://developer.roblox.com/en-us/api-reference/property/Humanoid/CameraOffset

1 Like

Hadn’t even thought about using a camera offset, thank you very much

This is the script I’ve come up with for this, problem is the Camera doesn’t move with the mouse. Reason I’m not using the other script is because I’m wanting to make this compatible with Xbox as well as computer. How would I make the camera move along with the mouse? This is my script, I’m still fairly new to camera manipulation.

local ContextActionService = game:GetService("ContextActionService")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
 
local camera = workspace.CurrentCamera
local cameraOffset = Vector3.new(2.5,0,0)
local player = Players.LocalPlayer
local humanoid = player.Character.Humanoid

local rootPart = player.Character.HumanoidRootPart

local cameraAngleX = 0
local cameraAngleY = 0

local ignited = game.ReplicatedStorage.SaberAssets.Ignited

local function shiftLockSetup()
	if ignited.Value == true then
		humanoid.CameraOffset = cameraOffset
		humanoid.AutoRotate = false
		UserInputService.MouseBehavior =	Enum.MouseBehavior.LockCenter
	else
		humanoid.CameraOffset = Vector3.new(0,0,0)
		UserInputService.MouseBehavior =	Enum.MouseBehavior.Default
		humanoid.AutoRotate = true
	end
end

RunService.RenderStepped:Connect(shiftLockSetup)

I’ve been working as much as I could to find a workaround but so far there’s nothing I’ve been able to figure out.

By interpolating the camera using a last camera position reference that’s where I cannot even get the camera in the right spot. I want the camera to interpolate to the default perspective (which would be easily done with CameraOffset), although I cannot do this because the CameraOffset can only let you view an object as if it’s orbital, so attempting to make the shoulder camera with an orbital camera is quite difficult enough. What I want is to mimic the mechanics of running freely with the ability of AutoRotate, but this cannot be done until either there’s a workaround for this issue or another way to handle it.

Me and you have the same requests for making the camera work. I think we both need the same thing (quite exactly).

Edit: Not sure if I over complicated it, but I have found some sources that’ve helped me. It just takes a few searches & you’ll eventually fid it.