Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

[Solved] How do I calculate a point with a given distance and direction?

Asked by 10 years ago

So I have a script that, when I click, a part moves from it's position to the mouse.Hit.p position, but I also want it to be limited to a maximum distance, how would I recalculate the target position to a new point with the maximum distance in the same direction.

I recreated my situation below, copy and paste it in a new project. Put it in a LocalScript in StarterPack.

local m = game.Players.LocalPlayer:GetMouse()
local p = Instance.new("Part", workspace)
local v = Instance.new("BodyVelocity", p)
local c
p.Anchored = true
local point
wait()

function getDir(vec)
    local lenSquared = vec.magnitude^2
    local invSqrt = 1 / math.sqrt(lenSquared)
    return Vector3.new(vec.x * invSqrt, vec.y * invSqrt, vec.z * invSqrt)
end

function ShowPointer(target)
    local point = Instance.new("Part", game.Workspace)
    point.Name = "Point"
    point.Size = Vector3.new(1,1,1)
    point.CanCollide = false
    point.Anchored = true
    point.Position = target + Vector3.new(0,1,0)
    point.BrickColor = BrickColor.new(21)
    local mesh = Instance.new("BlockMesh", point)
    mesh.Scale = Vector3.new(0.3,1,0.3)
    return point
end

function Unweld()
    if p:FindFirstChild("Weld") then
        p.Weld:Destroy()
    end
end

function Weld(char)
    p.Anchored = false
    c = char
    local torso = c.Torso
    Unweld()
    local weld = Instance.new("Weld")
    weld.Part0 = p
    weld.Part1 = torso
    weld.Parent = p
    weld.C0 = CFrame.new(0,2,3)
    weld.C1 = CFrame.new()
end

function Move(target, maxDist)
    if c ~= game.Players.LocalPlayer.Character then return end
    p.Anchored = false
    Unweld()
    target = Vector3.new(target.X, p.Position.Y, target.Z)
    local dist = (target - p.Position).magnitude
    local dir = (target - p.Position).unit
    dist = math.min(dist,maxDist)
    target = dir*dist -- It works if I comment this line, but without the maxDist
    if point ~= nil then point:Destroy() end
    point = ShowPointer(target)
    p.BodyVelocity.velocity = getDir(dir) * 30.0
    while dist > 0.5 and wait() do dist = (target - p.Position).magnitude end
    p.BodyVelocity.velocity = Vector3.new(0,-10,0)
    p.Anchored = true
end

function OnButton2Up()
    Move(m.Hit.p, 10)
end

m.Button2Up:connect(OnButton2Up)
p.Touched:connect(function(hit)
    if hit.Parent:FindFirstChild("Humanoid") then
        Weld(hit.Parent)
    end
end)

If anything is unclear, please leave a comment.

0
When I test it it seems to more or less behave correctly. BlueTaslem 18071 — 10y
0
Well. The point is that, when I add dir*dist, the part still goes in the right direction, but look at the pointer. Also, keep in mind that it should only work when the part is welded to the player. I didn't add that to the script above, but that's the case in my full project. damagex443 325 — 10y
0
Alright, I got it to work. After all it turned out to be that I have to add the p.Position to the outcome of dir*dist. Kind of obvious now that I think of it. damagex443 325 — 10y

1 answer

Log in to vote
4
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
10 years ago

Any vector is a distance (a number) in a particular direction (a vector).

Since a scalar (number) multiplied by a direction vector is another vector (scaled by the scalar), a vector indicating direction is usually defined as length 1, so that dir * len has length len.

A vector of length 1 is called a unit vector. ROBLOX gives us a function to get the unit vector of any given vector through the .unit property.


displacement = target - position
-- The vector going from where we are (position)
-- to where we are going [toward] (target)

direction = displacement.unit
distance = displacement.magnitude

We can get displacement back by just multiplying direction and distance. If we want to make distance at most maxDist, though, we can limit it, for example, by using math.min:

distance = math.min( distance, maxDist )
-- `distance` is now the smaller of `distance` and `maxDist`

And to get the new target point at most maxDist away, we just multiply:

newTarget = direction * distance

One warning: If position and target are the same, the unit vector is undefined and may cause problems if you forget about that.

A simple check before doing too much with it is to make sure distance is at least, say, 0.001.

0
Somehow the angle of the target changes when multiplying direction by distance. damagex443 325 — 10y
0
I recreated my situation in the first post, you can copy and paste the full script in a new project. LocalScript in StarterPack, but I guess you know. damagex443 325 — 10y
0
Could you help me out on this one? This really messes with my head. damagex443 325 — 10y
Ad

Answer this question