How intensive is .Magnitude?

Basically, I am going to be performing this calculation:

while wait(.01) do
    local distance = (player.Character.HumanoidRootPart.Position - Mouse.Hit).magnitude
end

How intensive is this and is it any better to be using Player:DistanceFromCharacter(Mouse.Hit)

This calculation is being done in a local script (if that makes a difference)
Thanks in advance! :smile:

First of all, Happy Birthday!

Iā€™d recommend using Player:DistanceFromCharacter for a few reasons:

  1. Who knows how long the HumanoidRootPart will be around? Not long ago, it didnā€™t exist. Using DistanceFromCharacter allows Roblox to adjust how the distance is found while still achieving the same end goal.
  2. DistanceFromCharacter require less indexing in lua, and allows for shortcuts and optimizations on the C++ side, since C++ has access to information Lua doesnā€™t and is much, much faster.
  3. It looks cleaner and is even labeled with its purpose

However it should be noted that when it comes to performance, data is key. Weā€™ll never know until we test it!

26 Likes

Thank you!


That makes sense.
I suppose it I start experiencing performence issues I can always cut down on the amount of times I am running the loop. :smile:

If you end up with performance issues due to how much it is running in a loop, then Iā€™d recommend not looping at all! Iā€™d have to know the use case to suggest an alternative, but usually loops dealing with distances in Lua can be avoided by things like bounding sphere hit boxes being welded onto players or other parts.

I donā€™t think you will run into any performance issues with either method, unless youā€™re calling it like 10 million times a frame.

4 Likes

Itā€™s not intensive at all, but wait() and wait(n) are inconsistent in their timing and will take longer than you might expect. I would recommend using a RunService.Heartbeat connection, especially for something as non-intensive as this.

2 Likes

Alright thanks, iā€™ll switch it over

Didnā€™t even know this was a function. I will keep this in mind for sure.

Worth mentioning that every time you access Mouse.Hit, the engine actually performs a raycast behind the scenes to determine what part is being hit ā€” this is the ā€œintensiveā€ part of that line of code. Then computing the distance between that and the HRPā€™s position is extremely cheap in comparison to that raycast.

But like others said, as you only run this code once per frame (or even fewer times using wait), this single raycast per frame wonā€™t cause any issues anyway.

3 Likes

Player:DistanceFromCharacter is my go-to, however if you like using .Magnitude, Iā€™d recommend using player.Character.PrimaryPart instead of assuming the player has a HumanoidRootPart. Happy Birthday!

Going to leave this here for completeness of the question for future.

I heard using magnitude is slow due to the square root. Calling it every ā€œ.01ā€ seconds should be okay though.

If you ever have to call it a lot more to do some kind of distance check, I would recommend using the Pythagorean theorem without squaring. General idea:

local v = (player.Character.HumanoidRootPart.Position - Mouse.Hit.p)
local distanceSquared = v.x^2 + v.y^2 + v.z^2
if distanceSquared < 25 then -- 25 would actually be 5 studs (5^2 = 25)
    -- do stuff
    local dis = math.sqrt(distanceSquared)  -- use this to draw lazerbeam or whatever
end

You donā€™t need this unless you are doing a large amount of distance checks in a short amount of time.

5 Likes

In the real world itā€™s extremely unlikely Roblox is going to just randomly remove HumanoidRootPart and if they did they would warn us about it.

You can safely assume the character will have HumanoidRootPart.

3 Likes

To be pedantic, this isnā€™t waiting .01 seconds. Given wait(n) if n < 0.03, itā€™ll be treated as wait(0.03) (aka wait())

As a fair warning, unless it has been changed since Iā€™ve last used it, DistanceFromCharacter will return 0 if the character is destroyed/missing/not spawned yet. (This could trigger some false positives if you were not expecting this case) Iā€™ve historically avoided this function because of this property. (Also this call has to be sent through the C++/Lua bridge which slows it down a bit)

On the other hand, magnitude is fairly inexpensive if used a single time per frame. You could always benchmark this (typically done by calling your function with magnitude a few thousand times in a frame and measuring the time elapsed before and after every operation) on different machines/devices if you want to know the factor of the cost for your specfic usecase.

1 Like

I donā€™t think i will be affected by this because it is taking place within a tool that you manually go and find. Thanks for the insight though! :smile:

1 Like

You are comparing apples to oranges: Mouse.Hit is a CFrame; not a Vector3

No idea how intense .Magnitude is, but you may wait(.1), or maybe wait(.4): No Avatar moves that fast, and no one clicks that much.

Also, I will answer your next post before you posts it:
Why is Distance never less than 3 studs, or if using DistanceFromCharacter, why is Distance never less than 5 studs?

Most often people say, ā€œWhy is .magnitude is so inaccurateā€?
They forget that the Torso is 3 studs off the ground; yet they are measuring from the center of the Torso to the spot Clicked on the BasePlate. (DistanceFromCharacter measures from the center of the Head)
.
If you are trying to find the distance between the character, and a spot on the ā€œBasePlateā€ (You have not stated what u r trying to do), you are going to have to use .magnitude. In almost all . magnitude calculations involving an Avatar, you are going to have to strip the Y value from the calculation.

You might want this:

while wait(.1) do
local Root = player.Character.HumanoidRootPart.Position
local Hit = Mouse.Hit.p
local distance = (Vector3.new(Root.x, 0, Root.z) - Vector3.new(Hit.x, 0, Hit.z)).magnitude

if distance < 1 then
      print("We are close enough", distance)
end

end

Not tested.

If you want to use DistanceFromCharacter, replace the Y Value with the Heads

print(player:DistanceFromCharacter(Vector3.new(Hit.x, [The Heads Y Value], Hit.z)))

Good Luck

3 Likes

P.S. You mentioned a Tool: If you are ā€œdiggingā€ into the ground, it might be better to measure from the Tool, instead of from the Root.

1 Like

PrimaryPart can be nil too. PrimaryPart is a BasePart reference. Both can be assumed to exist and both can return nil, thereā€™s no difference except for one being indexed by a property.

1 Like

You can check if it exists. But using Player:DistranceFromCharacter is the best

Thatā€™s repeating the point I was making. Both need to be checked for existence because both can yield a nil, in which attempting to operate on a nil value will throw an error.

As the solved reply stated, DistanceFromCharacter has the work pushed to the engine backend and only a few internal changes are necessary - itā€™ll always work as intended aside from that.

1 Like