Generating a part from Point A to Point B

How would I go with generating a part with a variable scale and orientation? Let’s say that I want a part to start from a specific point, and finish to another one.

Example

How would I calculate the space between point A and B, and the orientation which in this case is 0?

2 Likes

If I understand this question correctly, to calculate the distance between point A and B you’d need to calculate the magnitude between both spaces.

local magnitude = (workspace.Part1.Position - workspace.Part2.Position).Magnitude
print(magnitude)

You would want to place the connecting part midway between A and B, and then size it to the magnitude of the distance between both points. If the points can have different orientations, you can use CFrames

I used this sample code to have a part connect two points:

local direction = pointA - pointB -- pointA and pointB are both Vector3's

part.CFrame = CFrame.new(pointB + direction/2, pointB)
part.Size = Vector3.new(1, 1, direction.Magnitude)
6 Likes

First, calculate the distance between the two:

local dist = (pointB - pointA).magnitude

Stretch the part to cover the distance (on its Z-axis):

part.Size = Vector3.new(1, 1, dist)

Then, if you do

part.CFrame = CFrame.new(pointA, pointB)

the part will sit at A and point it’s front (i.e. -Z AKA the skinny side) face towards B.

Finally modify that last line to move it foward by half the distance:

-- final code:
local dist = (pointB - pointA).magnitude
part.Size = Vector3.new(1, 1, dist)
part.CFrame = CFrame.new(pointA, pointB) * CFrame.new(0, 0, -dist/2);

edit: I like @MayorGnarwhal’s better

5 Likes

Small critique: swap the Size and CFrame lines so that the position isn’t recalculated when you set the size.

1 Like

Position isn’t changed by setting the size of a part. Position is measured by the center point of the part, and changing the size will keep that center point. It doesn’t really matter which operation is done first.

1 Like

I tried all of them, but they didn’t work. Here is the script I used (your’s with some manipulations):

local pointA = workspace.Part1.Position
local pointB = workspace.Part2.Position
local direction = pointA - pointB 
local part = Instance.new("Part")

part.CFrame = CFrame.new(pointB + direction/2, pointB)
part.Size = Vector3.new(1, 1, direction.Magnitude)

Any ideas?

Also, would this work with UI?

Oh, maybe that’s new behavior. I could have sworn that changing the size or position of a part would make it jump to the top of any intersecting parts.

That should do something – what error are you seeing? And what do you mean “would this work with UI”?

Here is the thing, I see no error. It says that it works fine!
What I mean by “would this work with UI” is that could you calculate the magnitude for GUI objects?

  1. You never parented the part to workspace :slight_smile:
  2. What do you mean though:
  • Drawing a GUI line between two 2D positions
  • Drawing a GUI line between the screen-projected positions of two 3D positions
  • Stretching a Part between two 2D positions projected into 3D (what would that even mean?)

For UI objects,

Magnitude would be
( ObjectB.AbsolutePosition - ObjectA.AbsolutePosition ).Magnitude

Orientation would require trigonometry. If you wanted angle from the X axis, you would do
math.atan2( ObjectB.AbsolutePosition.Y - ObjectA.AbsolutePosition.Y, ObjectB.AbsolutePosition.X - ObjectA.AbsolutePosition.X )

I can’t remember which way round all the notations end up, but if your rotation ends up out by 90 degrees, swap the X’s and Y’s. And if the rotation ends up being the wrong direction (clockwise instead of anticlockwise or vice versa) then just swap the sign of the atan result as I think atan is counter clockwise and UI rotation is clockwise.

1 Like

You can use Vector3.new, such as if you want it to tp, then you can do from “this position” use vector3.new and write the new position in Vector3.new(“x,y,z”) or you can do multiple Vector3.new such as

Vector3.new("x,y,z")
wait(3)
Vector3.new("x,y,z")
wait(3)
and so on...

The issue with this code is you never parent the part.

part.Parent = workspace should be added at the bottom.

The frame does not appear…
Here is the script"

local Plr = game.Players.LocalPlayer
local Gui = Plr:WaitForChild("PlayerGUI")
local ObjectA = Gui.ObjectA
local ObjectB = Gui.ObjectB

local Frame = Instance.new("Frame")
Frame.Parent = Gui
Frame.CFrame = math.atan2( ObjectB.AbsolutePosition.Y - ObjectA.AbsolutePosition.Y, ObjectB.AbsolutePosition.X - ObjectA.AbsolutePosition.X )
Frame.Size = Vector3.new(1, 1, ( ObjectB.AbsolutePosition - ObjectA.AbsolutePosition ).Magnitude)


Did I do it correctly?

You can’t use Vector3 or CFrame for GUI size and position. You need UDim2

local Plr = game.Players.LocalPlayer
local Gui = Plr:WaitForChild("PlayerGui"):WaitForChild("ScreenGui")
local ObjectA = Gui:WaitForChild("ObjectA")
local ObjectB = Gui:WaitForChild("ObjectB")

local Frame = Instance.new("Frame")
Frame.Parent = Gui
local positionA = ObjectA.AbsolutePosition + ObjectA.AbsoluteSize / 2
local positionB = ObjectB.AbsolutePosition + ObjectB.AbsoluteSize / 2
local avgPosition = ( positionA + positionB ) / 2
Frame.AnchorPoint = Vector2.new( 0.5, 0.5 )
Frame.Position = UDim2.new( 0, avgPosition.X, 0, avgPosition.Y )
Frame.Rotation = math.deg( math.atan2( positionB.Y - positionA.Y, positionB.X - positionA.X ) )
Frame.Size = UDim2.new(0, ( positionB - positionA ).Magnitude, 0, 4 )

I’m on mobile right now so I can’t test it but give that a go.

Edit: Updated the code.

1 Like

Still, nothing happens. no errors, no frame…

Possibly due to misspelling PlayerGui, and not having a ScreenGui inside of it (GuiObjects only show inside of a ScreenGui, SurfaceGui or BillboardGui).

If you look at the output you’d notice it warning you of a potential infinite wait. Analysing the output window can be very helpful to identifying mistakes like that.
image

I tested myself and fixed a few issues regarding AnchorPoint (so that Position is measured from the centre of the object) and converting the rotation to degrees (as Rotation is in degrees, the math functions work in radians).

I’ve updated the code accordingly - put your ObjectA and ObjectB inside of a ScreenGui in StarterGui and your LocalScript somewhere like StarterPlayerScripts and hit Play.

1 Like

This is what happens:

It won’t go to the right position nor rotation. Here is the updated script:

local Plr = game.Players.LocalPlayer
local Gui = Plr:WaitForChild("PlayerGui")
local ObjectA = Gui.ScreenGui.ObjectA
local ObjectB = Gui.ScreenGui.ObjectB

local Frame = Instance.new("Frame")
Frame.Parent = Gui.ScreenGui
local avgPosition = (ObjectA.AbsolutePosition + ObjectB.AbsolutePosition)/2
Frame.Position = UDim2.new(0,avgPosition.X,0,avgPosition.Y)
Frame.Rotation = math.atan2( ObjectB.AbsolutePosition.Y - ObjectA.AbsolutePosition.Y, ObjectB.AbsolutePosition.X - ObjectA.AbsolutePosition.X )
Frame.Size = UDim2.new(0, ( ObjectB.AbsolutePosition - ObjectA.AbsolutePosition ).Magnitude, 0, 4)