Billboard gui not moving with part

I am trying to make a damage indicator that moves in a curved fashion away from the enemy.

In order to do this I am using a part with a billboard gui inside.

As you can see on the video below, the gui moves fine along the x/z axis however doesnt move with the parts Y position, any ideas on how to fix this?

We can’t tell how you’re doing it without seeing the script.
Please Copy/Paste that section of code here from Studio and put 3 backticks (```) before and after it so it formats properly in the post.

curve path module:

local function createTween(part: BasePart,targetPosition:Vector3)
	return tweenService:Create(part,tweenInfo,{Position = targetPosition})
end

local module = {}


local function curvePath(startPosition, endPosition, height)
	return function(Time)
		local x = (1-Time) * startPosition.X + Time * endPosition.X
		local y = (1-Time) * startPosition.Y + Time * endPosition.Y + math.sin(Time * math.pi) * height
		local z = (1-Time) * startPosition.Z + Time * endPosition.Z
			
		return Vector3.new(x,y,z)
	end
end

function module.run(part,targetPos)
	local startPosition = part.Position
	
	local tween = createTween(part,targetPos)
	tween:Play()
	
	local startTime = tick()
	runServiceEvent = runService.RenderStepped:Connect(function()
		local Time = (tick()-startTime) / tweenInfo.Time
		
		if Time > 1 then
			
			part.Position = targetPos
			
			return
		end
		
		part.Position = curvePath(startPosition,targetPos,height)(Time)
		
	end)
	
	tween.Completed:Connect(function()
		part:Destroy()
		runServiceEvent = nil
	end)
end

other script

local function indicatorHandler(enemy,damage)
	local newIndicator = healthIndicatorTemp:Clone()
	newIndicator.Position = enemy.HumanoidRootPart.Position
	newIndicator.Parent = workspace
	
	local randomDirection = Vector3.new(math.random()-0.5,0,math.random()-0.5).Unit
	local pos = enemy.HumanoidRootPart.Position + randomDirection * distance
	
	curvePath.run(newIndicator,pos)
end

This is probably due to a discrepancy between how the tween is updating the part’s position and how the RenderStepped connection is updating the position of the part with a curved path.

This should fix the issue where the GUI was not moving properly along the Y-axis and give you the desired curved motion for your damage indicator.

local runService = game:GetService("RunService")

local module = {}

local function curvePath(startPosition, endPosition, height)
    return function(Time)
        -- Interpolating X, Z positions linearly and adding height effect to Y position
        local x = (1 - Time) * startPosition.X + Time * endPosition.X
        local y = (1 - Time) * startPosition.Y + Time * endPosition.Y + math.sin(Time * math.pi) * height
        local z = (1 - Time) * startPosition.Z + Time * endPosition.Z

        return Vector3.new(x, y, z)
    end
end

function module.run(part, targetPos, height)
    local startPosition = part.Position
    local startTime = tick()
    local duration = 1 -- You can modify this to change how long it takes for the indicator to move

    local runServiceEvent
    runServiceEvent = runService.RenderStepped:Connect(function()
        local elapsedTime = tick() - startTime
        local Time = elapsedTime / duration

        if Time > 1 then
 
            part.Position = targetPos
            runServiceEvent:Disconnect()
            runServiceEvent = nil
            part:Destroy()
            return
        end

        -- Update part's position along the curve
        part.Position = curvePath(startPosition, targetPos, height)(Time)
    end)
end

return module

Since you are using a custom curve function to update the position, I removed the tween-related code. This avoids conflicting updates to the part’s position.

local function indicatorHandler(enemy, damage)
    local newIndicator = healthIndicatorTemp:Clone()
    newIndicator.Position = enemy.HumanoidRootPart.Position
    newIndicator.Parent = workspace

    local randomDirection = Vector3.new(math.random() - 0.5, 0, math.random() - 0.5).Unit
    local pos = enemy.HumanoidRootPart.Position + randomDirection * distance


    local height = 5
    curvePath.run(newIndicator, pos, height)
end

Thanks for your help, this worked perfectly!

1 Like

Your welcome, I am glad to help!