I was working on a camera module using springs to create a sort of dragging behind the player effect, the camera works pretty well but there’s one big problem.
Example of what I mean:
The character is super jittery in the clip for some reason and I’m not sure what’s causing it.
Here’s the spring module I’m using:
The main portion of the camera script
local cameraSubject = CameraSubject:Clone()
cameraSubject.Parent = self.hrp
local positionSpring = Spring.new(Vector3.new())
positionSpring.d = 0.8
positionSpring.s = 15
local bodyGyro = Instance.new("BodyGyro")
bodyGyro.MaxTorque = Vector3.new(0,4e5,0)
bodyGyro.P = 4e5
bodyGyro.Parent = self.hrp
local cameraAngleX = 0
local cameraAngleY = 0
local cameraSubjectOffset = CFrame.new(0,4,0)
local actualOffset = CFrame.new(0,0,12)
UserInputService.InputChanged:Connect(function(inputObject)
if (inputObject.UserInputType == Enum.UserInputType.MouseMovement) 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
bodyGyro.CFrame = bodyGyro.CFrame * CFrame.Angles(0, math.rad(-inputObject.Delta.X), 0)
end
end)
RunService:BindToRenderStep("Camera",Enum.RenderPriority.Camera.Value + 3,function(dt)
local camera = workspace.CurrentCamera
camera.CameraType = Enum.CameraType.Scriptable
UserInputService.MouseBehavior = self.shiftLock and Enum.MouseBehavior.LockCenter or UserInputService.MouseBehavior
self.humanoid.AutoRotate = not self.shiftLock
bodyGyro.Parent = self.shiftLock and self.hrp or nil
cameraSubject.CFrame = self.hrp.CFrame:ToWorldSpace(cameraSubjectOffset)
local cameraCFrameGoal = cameraSubject.CFrame
local cameraPositionGoal = cameraCFrameGoal.Position
positionSpring.t = cameraPositionGoal
local cameraPosition = positionSpring.p
local finalCameraCFrame = (CFrame.new(cameraPosition) * CFrame.Angles(0, math.rad(cameraAngleX), 0) * CFrame.Angles(math.rad(cameraAngleY), 0, 0)):ToWorldSpace(CFrame.new(actualOffset.X, actualOffset.Y, actualOffset.Z))
camera.CFrame = finalCameraCFrame
end)
I thought the problem might’ve been that so I tried tweening and lerping it although the camera was still jittering, honestly I have no idea why it’s happening
might just have to settle for a boring regular camera :((
Also tried playing around with render priority but that change anything either
The problem is that your spring is smoother than the actual movement of the physical part (which can actually bit a bit jerky at times). So the stuttering is actually the part and not the camera.
The way to fix this is to always base the first part of your camera equation by setting it to the CFrame of the part you’re following. And then add any offsets to it.
local subjectCFrame = cameraSubject.CFrame
camera.CFrame = subjectCFrame
But that will just give you a static camera without the spring effect. To add the spring, it’s a bit more tricky now, since you can’t just base it off the raw input of the spring anymore. We need the offset position, not world position.
There’s a bunch of different ways to go about doing that. One way would be to do something like this:
local subjectCFrame = cameraSubject.CFrame
spring.Target = subjectCFrame.Position
local posOffset = spring.Position - subjectCFrame.Position
camera.CFrame = subjectCFrame + posOffset
So here’s the new version, it’s still going wonky, probably something wrong with my implementation because my brain has been thoroughly fried by the jittering for the last couple of hours
updated code
----- Services -----
local UserInputService = game:GetService("UserInputService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
----- Module Scripts -----
local Spring = require(script:WaitForChild("Spring"))
local Maid = require(ReplicatedStorage:WaitForChild("Maid"))
----- Private Variables -----
local CameraSubject = script:WaitForChild("CameraSubject")
local MouseIcon = ""
local Camera = {}
Camera.__index = Camera
----- Public Methods -----
function Camera.new(player)
local self = setmetatable({},Camera)
self.maid = Maid.new()
self.player = player
self.character = player.Character or player.CharacterAdded:Wait()
self.humanoid = self.character:WaitForChild("Humanoid")
self.hrp = self.character:WaitForChild("HumanoidRootPart")
self.mouse = player:GetMouse()
self.cameraLock = true
self:initialise()
return self
end
function Camera:initialise()
local cameraSubject = CameraSubject:Clone()
cameraSubject.Parent = self.hrp
local spring = Spring.new(Vector3.new(),time)
spring.d = 0.8
spring.s = 15
local bodyGyro = Instance.new("BodyGyro")
bodyGyro.MaxTorque = Vector3.new(0,4e5,0)
bodyGyro.P = 4e5
bodyGyro.Parent = self.hrp
local cameraAngleX = 0
local cameraAngleY = 0
local cameraSubjectOffset = CFrame.new(0,4,12)
local actualOffset = CFrame.new(0,0,12)
self.maid:GiveTask(UserInputService.InputChanged:Connect(function(inputObject)
if (inputObject.UserInputType == Enum.UserInputType.MouseMovement) 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
bodyGyro.CFrame = bodyGyro.CFrame * CFrame.Angles(0, math.rad(-inputObject.Delta.X), 0)
end
end))
self.maid:GiveTask(RunService.Heartbeat:Connect(function(dt)
local camera = workspace.CurrentCamera
camera.CameraType = Enum.CameraType.Scriptable
UserInputService.MouseBehavior = self.cameraLock and Enum.MouseBehavior.LockCenter or UserInputService.MouseBehavior
self.humanoid.AutoRotate = not self.cameraLock
bodyGyro.Parent = self.cameraLock and self.hrp or nil
cameraSubject.Position = self.hrp.CFrame:ToWorldSpace(cameraSubjectOffset).Position
local subjectCFrame = cameraSubject.CFrame
spring.t = subjectCFrame.Position
local posOffset = spring.Position - subjectCFrame.Position
camera.CFrame = subjectCFrame + posOffset
camera.CFrame = camera.CFrame * CFrame.Angles(0, math.rad(cameraAngleX), 0) * CFrame.Angles(math.rad(cameraAngleY), 0, 0)
end))
end
function Camera:Destroy()
self.maid:DoCleaning()
end
return Camera