Smooth floating/player tracking orbs

Hey! So I was trying to recreate the floating system used to make these balls follow the player but I was running into some issues so if you have a smooth way to achieve this affect let me know!

I first tried using tween by couldn’t get both the gradual up-down floating to work along side following behind the player so I looked at some stuff with AlignPosition/Orientation but couldn’t get that to work either. If you’ve got any ideas please share!.


Video: @ZetsuboWhite on X

1 Like
local vertHover = Instance.new("CFrameValue")


task.spawn(function()
	
	while true do
		while true do
			TS:Create(ElectroOrb1, TweenInfo.new(.5, Enum.EasingStyle.Cubic, Enum.EasingDirection.InOut), {CFrame = CFrame.new(hrp.Position.X, vertHover.Value.Y, hrp.Position.Z * 1)})
		end
	end
end)

while true do
	task.wait(hovertime)
	local Up = TS:Create(vertHover, TweenInfo.new(hovertime, Enum.EasingStyle.Cubic, Enum.EasingDirection.InOut), {Value = vertHover.Value * CFrame.new(0,1,0) }):Play()
	task.wait(hovertime)
	local Up = TS:Create(vertHover, TweenInfo.new(hovertime, Enum.EasingStyle.Cubic, Enum.EasingDirection.InOut), {Value = vertHover.Value * CFrame.new(0,-1,0) }):Play()
end

I couldnt figure out a way to tween X, Y, and Z values seperately without compiling them into a single CFrame. I need some help :sweat_smile:

First of all, do not use while loops in this case, as they will drain much of the memory and not follow the player’s FPS. Using RunService is way more appropriate.

To implement the smooth movement of the ElectroOrbs, you can make tweens; however, I believe it’s better to use sine waves and lerp, updating the position of the orbs whenever the player moves.

local RS = game:GetService("RunService")

local amplitude = .1 -- How much does the wave go up and down
local speed = 2 -- The speed at which the orb oscillates
local follow = 1 -- The speed at which the orb follows the player

RS.Heartbeat:Connect(function(dt)
    local t = os.clock()
    local offset = math.sin(t * speed) * amplitude

    local target = hrp.Position + Vector3.new(0, offset, 0)

    ElectroOrb1.Position = ElectroOrb1.Position:Lerp(target, math.clamp(dt * follow, 0, 1))
    
    ElectroOrb1.CFrame = CFrame.new(ElectroOrb1.Position)
end)

Tell me if this works.

1 Like

Ended up working great :sob:.

I guess I’m not mathematically inclined enough to think about using a sin curve outside of tweenstyle. Is there a way to easily add offset relevant to the player’s orientation? say the ball floats 2 studs behind the character regardless of what way they are facing (instead of always being 1 stud offset on the world’s Z axis)?

1 Like

That’s great to hear!

Yes, there definitely is! What you want to achieve is to make the ball follow the player’s back position, right? You can use LookVector for it.

local RS = game:GetService("RunService")

local amplitude = .1 -- How much does the wave go up and down
local speed = 2 -- The speed at which the orb oscillates
local follow = 1 -- The speed at which the orb follows the player

RS.Heartbeat:Connect(function(dt)
    local t = os.clock()
    local offset = math.sin(t * speed) * amplitude

    local behindPosition = hrp.Position - (hrp.CFrame.LookVector * 2) -- Determines the back of the player moved by two studs. The negative of the LookVector is the same as getting the opposite direction of it.
    local target = behindPosition + Vector3.new(0, offset, 0) -- updates the position so it includes the behind position.

    ElectroOrb1.Position = ElectroOrb1.Position:Lerp(target, math.clamp(dt * follow, 0, 1))
    
    ElectroOrb1.CFrame = CFrame.new(ElectroOrb1.Position)
end)

Tell me if this works well. I can’t test, so it may result in an error or another; nothing we can’t solve, though!

1 Like

Haha thanks for that! Also found out I can use left/right or X Vectors to achieve the same effect perpendicularly. You’ve been a big help thanks again. :slight_smile:

1 Like

Yes! You can achieve that by using RightVector, LeftVector… there is no problem, as long as you mess up with the values so you can find the “player’s back” efficiently. I’m glad I’ve solved you problem ^^, have a nice day/night.

1 Like