How do I make this not jittery?

So I’m trying to replicate Phighting!'s UI style which looks 3D and I’ve somewhat created mine to be similar. However, there seems to be an issue. When I’m walking or if the camera has very drastic movements it jitters which looks laggy. How can I fix this?

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")

local PlayerCamera = workspace.CurrentCamera
local UIFolder = ReplicatedStorage.UI:Clone()

UIFolder.Parent = PlayerCamera

local HealthPart = UIFolder:FindFirstChild("Health")

if HealthPart then
	local distanceOffset = 2.4
	local screenOffset = Vector2.new(-1.4, -1.3)

	local function updateHealthPart()
		local camCF = PlayerCamera.CFrame
		local offset = camCF.RightVector * screenOffset.X + camCF.UpVector * screenOffset.Y
		local targetPosition = camCF.Position + camCF.LookVector * distanceOffset + offset

		local angleOffset = CFrame.Angles(0, math.rad(15), math.rad(-8))
		local targetCFrame = CFrame.new(targetPosition, targetPosition + camCF.LookVector) * angleOffset

		local tween = TweenService:Create(HealthPart, TweenInfo.new(0, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut), {CFrame = targetCFrame})
		tween:Play()
		
		tween.Completed:Connect(function()
			tween:Destroy()
		end)
	end

	updateHealthPart()
	PlayerCamera:GetPropertyChangedSignal("CFrame"):Connect(updateHealthPart)
end

1 Like

You should use RunService.HeartBeat connection. This fires every frame, you might also want to expand the tween time a little bit to appear more smooth, and try the Enum.EasingStyle.Sine wave.

Your current method might not be running every frame; on the client something like heartbeat isn’t performance heavy and ultimately everyone has a different FPS so somebody seeing 240 will see a jittery GUI while someone on 10 is just gonna see it teleport.

2 Likes

NEVER EVER MAKE TWEENS IN A RENDERSTEPPED cuz it can cause performance issues. Here’s my solution hopefully you like it. (Just copy this in a local script, put it in StarterCharacter)

local Rs = game:GetService("RunService")

local Test = Instance.new("Part", workspace)
Test.Anchored = true
Test.CanCollide = false

local distanceOffset = 2.4
local screenOffset = Vector2.new(-1.4, -1.3)

local Camera = workspace.CurrentCamera

function Follow()
	local camCF = Camera.CFrame
	local offset = camCF.RightVector * screenOffset.X + camCF.UpVector * screenOffset.Y
	local targetPosition = camCF.Position + camCF.LookVector * distanceOffset + offset

	local angleOffset = CFrame.Angles(0, math.rad(15), math.rad(-8))
	local targetCFrame = CFrame.new(targetPosition, targetPosition + camCF.LookVector) * angleOffset
	
	Test.CFrame = targetCFrame
end

Rs:BindToRenderStep("Attach",  Enum.RenderPriority.Camera.Value + 1, Follow)
2 Likes