3rd Person Over The Shoulder Camera

  1. What do you want to achieve? Keep it simple and clear!

I want to achieve a 3rd Person Over The Shoulder Camera where it’s in shiftlock while walking around but free cam when your standing still. I’m not asking for an entire system I would just like an example as to how this would function/work.

  1. What is the issue? Include screenshots / videos if possible!

Despite my best efforts I can’t get out of shiftlock smoothly and achieve the freecam I want when stationary.

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?

I’ve tried offsetting the camera and forcing shiftlock but it doesn’t look right. And I don’t know how the free cam part would work. And I have looked for solutions on the dev hub but either none of them work or I’m doing something wrong.

Any help is welcome, thanks!

For the freecam you could use LockCenter for the mouse, this would allow camera turning without holding the right mouse button, unless you want to require the right mouse button then ignore this, and for a more custom shiftlock you could rotate the character’s HRP to the camera’s Y axis of rotation every frame, use Lerp for smoothing if needed. As for detecting when they move and stop moving, you can check the Humanoid.MoveDirection, if it is 0,0,0 they are still, otherwise they are moving. If you didn’t want to account for jumping and falling you can check the X and Z only.

1 Like

What I would do is have both the default free cam system and a custom over-the shoulder-system running at the same time, then interpolate between the goal positions of the systems when the character starts and stops walking.

You can override the default camera while still letting it calculate by using some code like this:

local RunService = game:GetService("RunService")

local function calcShoulderCFrame()
	-- TODO: Write your over-shoulder camera system
end

local freecamFactor = 0
local function updateFreecamFactor()
	-- TODO: Calculate how much the camera should be in free cam mode
	-- by setting freecamFactor to [0-1], where 1 is 100% free cam
end

local function afterCamera(delta)
	local freecamCFrame = workspace.CurrentCamera.CFrame
	local overShoulderCFrame = calcShoulderCFrame()

	updateFreecamFactor()

	local goalCFrame = overShoulderCFrame:Lerp(freecamCFrame, freecamFactor)

	workspace.CurrentCamera.CFrame = goalCFrame
end

RunService:BindToRenderStep("After camera", Enum.RenderPriority.Camera.Value + 1, afterCamera)

What that code does is it lets the free rotation cam fully calculate it’s position, then overrides it with a combination of both the free cam CFrame and the over-shoulder cam CFrame, based on how much it should be using the over-shoulder CFrame (which should be determined by how “stationary” the player is (ex: how long they’ve been holding still).

One potential problem with that is that the “goalCFrame” (the combination of the two systems) gives feedback to the free cam (because setting the CFrame changes the position of the free cam). This might cause the free cam to be fully overridden unless the freecamFactor is very close to 1.

(I am assuming by free cam you mean the default camera behavior? If you’re using a real free cam, then code like this should work fine and you don’t even need to do the weird after camera stuff.)

1 Like

For the freecam you could use LockCenter for the mouse, this would allow camera turning without holding the right mouse button.
But the hard part is the script you need to do the perfect script that don’t have any problem when i was new in programming i tried to build this type of system and 1 error destroyed my project and you dont want to try this feeling working for long time and then you fail.

1 Like

Yea, that’s the problem with these kinds of systems. If you make one error and you can’t fix it, it’s all ruined.

I’ve made this exact thing, so I can definitely lend a helping hand. To check when the player is moving, there are two methods: Move Direction and Velocity. A player’s MoveDirection will be equal to zero when they’re not moving. The player’s HumanoidRootPart’s velocity’s magnitude will also be equal to zero when not moving (but you need to use math.floor on the magnitude since the slightest rotation will give it a velocity of something like 0.07). Run a loop using one of these methods to check whether the player is standing still. To optimize and use events, just use a getpropertychanged event on either the velocity or the movedirection. I’m sure you can easily find other documentation on how to make an over the shoulder camera, but If you’re having trouble I can provide some pointers. Turn off the autorotate property, and using a loop, constantly set the camera’s cframe to a root’s cframe plus some arbitrary offsets. Then using the same loop, once you have detected that the player has started moving, use a lerp, tween, or alignOrientation to rotate the root’s Y-axis towards where the camera is pointing in the world space.

1 Like

Is there any other way to force shift lock than lock center? It feels glitchy sometimes.

i have to go to school right now, but when i get home ill give you a walkthrough on how to make a simple over the shoulder system

1 Like

sorry but I’m a little busier than I expected today, try this video: https://www.youtube.com/watch?v=UsahcBf18jE&t=905s

1 Like

Nah your good bro i’m super busy this week to. Thanks for your help!

1 Like