Stuttering 2D Dynamic Camera

Hi! I’ve currently been working on my game for about two weeks and just decided to fix this problem with my camera system. I’ve already tried many different ways to fix this stutter that happens:

Example

In that demo you can see how the ball stutters. Here’s my current code:

Current Code
local TweenService = game:GetService('TweenService')
local RunService = game:GetService('RunService')

local Camera = workspace.CurrentCamera
local Ball = workspace.Ball
local CameraBrick = workspace.CameraBrick -- This brick is tweened to the balls position

local CameraOffset = 35
local CameraTweenInfo = TweenInfo.new(0.1, Enum.EasingStyle.Sine, Enum.EasingDirection.In, 0, false, 0) 
-- I realized that changing 'Enum.EasingStyle.Sine' to Sine instead of Linear made this stutter effect less noticeable

function RenderCamera()
	local cameraSubject = Ball
	local tween = TweenService:Create(CameraBrick, CameraTweenInfo, {Position = Vector3.new(cameraSubject.Position.X, cameraSubject.Position.Y, CameraOffset)})
	tween:Play()
	Camera.CFrame = CameraBrick.CFrame
end
RunService:BindToRenderStep('RenderCamera', 100, RenderCamera)

I previously tried to use Camera:Interpolate and it just made the stutter 10x worse.
I also tried to change the time the camera gets rendered, but that made no positive impact.
I tried making my own system to where the balls velocity changes the camera offset, but I got no good effect from that either.

Please note that the ball does not stutter. I tested this with this code:

This Code
local RunService = game:GetService('RunService')

local Camera = workspace.CurrentCamera
local Ball = workspace.Ball

function Render()
	Camera.Position = Ball.Position
end
RunService.RenderStepped:Conncet(Render)

With the code above, the camera smoothly follows the ball and does not stutter. Although it gives a very nasty effect and doesn’t add any camera sway… (I don’t want the ball to always be in the absolute center of the screen)

Any help would be appreciated! :slight_smile:

4 Likes
RunService.Stepped:Connect(function(deltaTime)
	local int = math.exp((-67)*deltaTime)
	local targetCFrame = CFrame.new(Ball.Position, Ball.Position + Vector3.new(Camera.CFrame.LookVector.X, 0, Camera.CFrame.LookVector.Z))
	
	Camera.CoordinateFrame = Camera.CoordinateFrame:Lerp(targetCFrame, int)
end)

Play around with the targetCFrame and hopefully you’ll get the desired effect

Whenever I run that code, the camera points off into space at nothing

You’re better off implementing it directly instead of constantly overwriting Tweens.

You can find the equation for sine easing online to calculate the amount to move the camera by between its current and goal positions.

You can then use CFrame:lerp to interpolate between the current and goal CFrames using the output from the sine easing as the alpha parameter.