The 100% Correct Formula for Distance UI / Bar

Ay boys!

I’ve noticed several posts where people are aiming to find the correct formula for creating a distance UI/Bar. For those unfamiliar, here’s an example of what a distance UI might look like:


Understanding the Problem

Before delving into the solution, let’s understand the problem at hand. We have three points:

  • The Start Point
  • The End Point
  • The Moving Point (in this case being the humanoid root part)

We aim to determine the relative position of The Moving Point in relation to a line segment defined by the Start Point and the End Point. The goal is to express this relationship as a percentage, ranging from 0 to 1, based on the Moving Point’s position between the Start Point and the End Point.


The Common Misconception

A commonly encountered formula involves taking the distance between the Moving Point and the Start Point or the Moving Point and the End Point, then dividing it by the total distance from the Start Point to the End Point.

local function getStartOffset(startPos: Vector3, endPos: Vector3, rootPos: Vector3)
    local rootDistanceFromStart = (endPos - rootPos).Magnitude
    local totalDistance = (endPos - startPos).Magnitude
    return math.clamp(rootDistanceFromStart / totalDistance, 0, 1)
end

Why This Is Incorrect

The flaw in this formula lies in its interpretation. If you move away from the Start Point by a distance equal to the total distance, it incorrectly yields a value of 1, implying you covered the distance from the Start Point to the End Point. However, you might just be moving away from the Start Point but not necessarily progressing towards the End Point,

In other words, if you’re just moving away from the Start Point a distance equal to the total distance, it will return 1 even when you’re not even close to the end point.


The Correct Formula

The correct formula involves taking the dot product of the vector from the Start Point to the Moving Point and the vector from the Start Point to the End Point. This result is then divided by the total distance squared.

local function getStartOffset(startPos: Vector3, endPos: Vector3, rootPos: Vector3)
    local vFromStartToRoot = (rootPos - startPos)
    local vFromStartToEnd = (endPos - startPos)
    local dotProduct = vFromStartToRoot:Dot(vFromStartToEnd)
    local startOffset = dotProduct / vFromStartToEnd.Magnitude^2
    return math.clamp(startOffset, 0, 1)
end

This Lua function efficiently computes the percentage and ensures it remains within the 0 to 1 range. You can apply the returned value as a Position X Scale component of the player thumbnail image label to move it horizontally along the UI Bar.

21 Likes