Hey! I’m trying to make the camera follow the player from behind with a bit of “weight” behind it, but it’s noticeably jittery.
I’ve tried every single variation on how to get deltaTime I could think of (heartbeat, renderstepped, directly hooking it up with the camera event) to no avail. I’ve also tried every method I could find for how to use deltaTime, equally to no avail.
The code you sent does the exact same thing, except it doesn’t take into account framerate, which, as you can see
is still choppy.
Therefore, something has to be done with the deltaTime. I just don’t know what it is. Documentations say to use 1 - (percentage) ^ deltaTime, even unrelated to roblox. And that clearly doesn’t work. This is why I’m so stumped about this…
Edit: The problem comes from :Lerp() being done between the stationary camera and the moving character. The new position of the character isn’t necessarily consistent each frame, which is why some sort of measure such as deltaTime needs to be employed. However I don’t think deltaTime might be the right tool for the job in this situation? Unsure which one would be and how you would go about using it.
The problem isn’t the camera movement but the character controller, you can see the background isn’t choppy. Roblox characters have always been choppy when walking, it’s just that normally the camera is fixed to the character so it’s barely noticeable.
local oldhrppos = hrp.Position
rs:BindToRenderStep("Target Camera", Enum.RenderPriority.Camera.Value + 1, function(deltaTime)
local newcframe = CFrame.new((hrp.CFrame * CFrame.new(0, 5, 12)).p, hrp.Position + Vector3.new(0, 2, 0))
local a = math.clamp((oldhrppos - hrp.Position).magnitude, 0.1, 0.5)
local a = a > 0.1 and a or 0.2
camera.CFrame = camera.CFrame:Lerp(newcframe, a)
oldhrppos = hrp.Position
end)
Video is extremely zoomed in, but in practice it is very difficult to notice. I would still rather have it follow the character 100% accurately, but if it means I have to make everything else jittery in the process I don’t know if it’ll be worth the effort.
Pretty sure you could do a hacky lerp formula using the MoveDirection property of the Humanoid so you can get perfect results relative to the character, while sacrificing the rest of the background being jittery.
Because, if so, how sure are you that your camera is staying as the Scriptable enum after the character is added? If that’s the desired result (above) I can share the source. The amount of weight in customizeable my example.
I am 100% sure. The code chunk I gave was a very very small piece of a currently ~700 line long script, so if there was anything wacky to do with spawning in, I would have noticed it, haha.
Result above is not what I desire. I am guessing you are using a bodymover on an invisible part? Because if so, I need the camera to really behave like a lerp, like without physics based momentum, if you get what I mean. Regardless I’ve tried bodymovers before and they just didn’t feel quite right.
No, I did not use something hacky like a body mover. It’s pure interpolation.
Result above is not what I desire
Then please explain better what is.“Without physics based momentum” I don’t understand what you’re asking for. Is the “smooth movement” of my camera the only issue with your “desire?”
Like this then? The swing weight and interpolation timeframes are adjustable as variables here. I’m recording at 27fps so excuse the choppiness of gif.
Here’s a full replication (designed to be a throw-in on a blank place).
local camera = workspace.CurrentCamera
local player = game.Players.LocalPlayer
local rs = game:GetService("RunService")
local tweenService = game:GetService("TweenService")
local uis = game:GetService("UserInputService")
local char = player.Character or player.CharacterAdded:Wait()
local hrp = char:WaitForChild("HumanoidRootPart")
-- This MUST be done after the character is added
camera.CameraType = Enum.CameraType.Scriptable
char.Humanoid.AutoRotate = false
local swingWeight = 0.5
local dragTimeframe = 125 -- in milliseconds
rs:BindToRenderStep("Target Camera", 201, function()
-- Replicate shift lock (just for my demonstration)
local targetPosition = hrp.Position + Vector3.new(0,0,200)
local cameraBasePosition = (hrp.CFrame * CFrame.new(0,5,12)).p -- 5 units above and 12 behind the hrp
char:SetPrimaryPartCFrame(CFrame.new(hrp.Position, targetPosition))
-- Begin camera drag adjustments
local offsetDirectionX = math.floor(char.Humanoid.MoveDirection.X) -- -1 is left and 1 is right
local offsetDirectionZ = math.floor(char.Humanoid.MoveDirection.Z) -- -1 is forward and 1 is backward
local cameraTargetPosition = hrp.Position + Vector3.new(0,0,200)
local nonAdjustCameraCFrame = CFrame.new(cameraBasePosition, cameraTargetPosition)
local adjustedCameraCFrame = nonAdjustCameraCFrame * CFrame.new(offsetDirectionX * swingWeight,0,offsetDirectionZ * swingWeight)
local tweenInfo = TweenInfo.new(dragTimeframe / 1000)
local tween = tweenService:Create(camera, tweenInfo, {CFrame = adjustedCameraCFrame})
tween:Play()
end)
What you’re looking for happens on line 23 and below. The lower the swingWeight value the more subtle the “drag.” The dragTimeframe can also be adjusted to change how smooth it happens in. A lower value is a sharper more instant change.
Hrmm… Are you sure that having a tween run every single rendered frame is a good idea for performance? You won’t see the tween regardless as it’s done during the rendering process… Unless I’m missing something.