Make camera smoothly follow moving part

Hello all. I have a script that, when the player dies, locks the camera in place and follows them. This script works properly, but perfectly follows the player’s head, which looks a little strange. Is there some way to make it smoothly follow the player’s head, so it lags behind a little? Here’s my current code and what it looks like in game:

local function CameraFollow()
	cam.CFrame = CFrame.new(cam.CFrame.Position, head.Position)
end


You can see especially when the player goes behind the camera, it snaps to the player’s head, and it just looks odd and rough.
Before you recommend I use TweenService, that just won’t work. The player’s head is constantly moving unpredictably and tweening would be too laggy.
Thanks.

1 Like

Would attaching the camera to HumanoidRootPart work?

1 Like

I already know how to follow the player. I’m asking how to make the camera smooth, so it doesn’t perfectly follow the player’s head, it should lag behind a little bit and move smoothly.

Did you try lerping the camera instead?
Edit: you could also try doing this:

get the CFrame position that the camera will point to, and wait 0.1 seconds and THEN move the camera to that position using TweenService. This will fix the solution of it lagging because it will “lag behind” just as you want it. ask if you want me to elaborate bceause am not sure if you understand

1 Like

I have not tried that. Could you give an example of how it could work?

I think you have the right idea with lerping the camera, but I would just lerp the camera direction instead of using TweenService.

local targetDir = head.Position - cam.CFrame.Position

-- Lerp from current direction to target.
-- 0.7 is the lerp amount, (lower will be slower/smoother)
local lerpedDir = cam.CFrame.LookVector:Lerp(targetDir, 0.7)

-- Apply new CFrame.
cam.CFrame = CFrame.new(Vector3.zero, lerpedDir) + cam.CFrame.Position
3 Likes

You could try using one of those spring functions to simulate dampening. Here’s one that I pulled out of the default freecam module (that comes with Studio) with slight modifications

Spring module
local Spring = {}

local pi2 = math.pi * 2
Spring.__index = Spring

function Spring.new(freq: number, pos: Vector3)
	local self = setmetatable({}, Spring)
	self.f = freq * pi2
	self.p = pos
	self.v = Vector3.zero
	return self
end

function Spring:Update(dt: number, goal: Vector3)
	local f: number = self.f
	local p0: Vector3 = self.p
	local v0: Vector3 = self.v

	local offset: Vector3 = goal - p0
	local decay: number = math.exp(-f * dt)

	local fdt: number = f * dt
	local p1: Vector3 = goal + (v0 * dt - offset * (fdt + 1)) * decay
	local v1: Vector3 = (fdt * (offset * f - v0) + v0) * decay

	self.p = p1
	self.v = v1

	return p1
end

function Spring:Reset(pos: Vector3)
	self.p = pos
	self.v = Vector3.zero
end

return Spring

It might look complicated, but it’s actually quite simple to use. You of course first create the springs:

local stiffness: number = 1.5 --how "stiff" the spring is
local Spring = require(script.SpringModule) --modulescript
...
local rotSpring = Spring.new(stiffness, Vector3.zero)

Then to prepare to use it, you initialize the position:

--whenever the player dies and the camera needs to start following the head:
rotSpring:Reset(head.Position)

Then to actually use it, you constantly update the spring with the new positions on every frame and use the result:

game:GetService('RunService').BindToRenderStep('track camera', Enum.RenderPriority.Camera.Value + 1, function(dt) --should probably be using .Stepped delta-time instead
    local pos = rotSpring:Update(dt, head.Position) --Spring will interpolate and return current position
    cam.CFrame = CFrame.lookAt(cam.CFrame.Position, pos) --Use the returned value
end)

(Note that all of these snippets are generalizations and shouldn’t be just copy and pasted into your game)

3 Likes