I’m trying to make a 3D health bar that is relative to the players camera and follows it. I initially just had the CFrame always being updated ever Stepped, which works perfectly except for the fact that it becomes really choppy when moving the camera quickly, and so I opted out for tween service.
The issue with this though, is that the tween never seems to play, the 3D health bar part does not move and stays in place at all times, but even after all of this I’m still getting completed print into the output. There are no error’s, and I’m confused why this is not working. Please help.
local healthBar = game:GetService("ReplicatedStorage"):WaitForChild("Assets"):WaitForChild("Player"):WaitForChild("healthBarGUI"):Clone()
healthBar.Parent = workspace
healthBar.CanCollide = false
local camera = workspace.CurrentCamera
game:GetService("RunService").Stepped:Connect(function()
local tween = game:GetService("TweenService"):Create(healthBar, TweenInfo.new(1, Enum.EasingStyle.Linear, Enum.EasingDirection.In, 0, false, .25), {
CFrame = camera.CFrame * CFrame.new(-25, 0, -20) * CFrame.Angles(math.rad(0), math.rad(180), math.rad(0))
}) -- The tween for tweening the healthBars position to the camera
tween:Play() -- Play's the tween
tween.Completed:Wait() -- Waits for the tween to be completed so that it can continue to tween it when the cframe of the camera changes.
print("completed") -- prints completed after the tween is completed, so that we can get an indication on if the tween has repeated again.
end)
I am confused, you are creating a tween that lasts for a whole second every single frame? This would be creating a very high amount of tweens and there is no need for TweenService here. Couldn’t you simply set the CFrame instead of tweening it?
As others have said you’re starting a new tween on ever Stepped, which is just a horrible idea. I see that the reason you’re doing this is because you want the healthBar to face the camera. You should play the tween outside of RunService firstly, and secondly, consider using a billboardGui if you wan the healthbar to always face the camera
You should use RunService:BindToRenderStep() with priority Enum.RenderPriority.Camera.Value + 1 to make it run after the Camera has updated its position. The reason it looks choppy is because you’re setting the cframe before the camera updates to the position that it renders at. This results in the part being always 1 frame behind the camera when rendered.
Do sum it up from the responses. You should use RunService:BindToRenderStep() with a priority above camera render priority to prevent chopiness.
In addition to tween spamming “completed”, you’re literally creating and playing new tween every physics step, which is why your console is flooded.
TweenService is a no-no in tasks that are ran every render cycle. For this reason, you should use CFrame:Lerp(goalCFrame, alpha), which returns linear interpolation between origin CFrame and CFrame goal based on alpha. You can have a calculated alpha using the formula I’ve made and been using a while ago 1-(1/10^(delta*strength). delta can be obtained from runservice, be it RenderStepped, Stepped, or Heartbeat, or Render step.
Through RenderStep you obtain delta as simple as that:
RunService:BindToRenderStep("healthbar", Enum.RenderPriority.Camera.Value + 1, function(delta: number)
print(`Time took for resumption: {delta}`)
end)
Same can be done with other signals so. You’re not limited to only render step.
TL;DR: Refrain from using TweenService in favor of CFrame:Lerp() and switch to RunService:BindToRenderStep() using 1-(1/10^(delta*strength) for alpha and healthBar.CFrame = healthBar.CFrame:Lerp(newCFrame, alpha) for healthbar positioning.
Why would you need to lerp the camera’s CFrame? I thought the OP’s issue was to have the 3D healthbar always on screen in the same spot, not have it smoothly interpolated.