I especially needed understand with the 3 last main lines ----> CFrame.Angles(math.pi/2,0,0);--rotate it so that the hand points that way weld.C0=CFrame.new();--set C0 to identity matrix so it is out of the equation weld.C1=desired_p1:inverse()*weld.Part0.CFrame;--same equation as shown above
local playa=game.Players.LocalPlayer; script.Parent.Selected:connect(function(mouse) while Wait() do local weld=playa.Character.Torso["Left Shoulder"]; --[[ p0=part0.CFrame c0=c0 p1=part1.CFrame c1=c1 p1*c1 == p0*c0 c1 == p1:inverse()*p0*c0 c0 == p0:inverse()*p1*c1 --]] local desired_p1=CFrame.new(--the CFrame that we want the arm to be at (weld.Part0.CFrame*CFrame.new(-1,1,0)).p,--the position we want mouse.hit.p--look at the mouse )* CFrame.Angles(math.pi/2,0,0);--rotate it so that the hand points that way weld.C0=CFrame.new();--set C0 to identity matrix so it is out of the equation weld.C1=desired_p1:inverse()*weld.Part0.CFrame;--same equation as shown above end end )
CFrames are position and orientation together. They are implemented as matrices, and thus have the properties of matrix addition, product, and inverse.
When you get the .CFrame
of a part, that is in world space -- it's relative to the world as a whole. Thus (0, 0, 0) is in the middle of the world, and (0, 1, 0) is up, etc.
You can instead imagine your position and orientation relative to another CFrame. For instance, the top surface of a part in its object space will always be (0, 1, 0) no matter how the part is tilted.
You can convert between Object Space and World Space using object:toWorldSpace(objectSpaceCFrame)
and object:toObjectSpace(worldSpaceCFrame)
.
For example, you can use :toObjectSpace
to find the distance between two parts:
local BRelativeToA = A.CFrame:toObjectSpace( B.CFrame ) print( BRelativeToA.p.magnitude ) -- distance between A and B
:toObjectSpace
will "undo" :toWorldSpace
and vice versa.
If A
and B
are CFrames, then A * B
means "B
, but relative to A
" -- A * B
is the same thing as A:toWorldSpace(B)
. This is exactly a matrix product.
local up = CFrame.new(0, 5, 0) local part = workspace.Part.CFrame local out = part * up -- the top of the part
A:inverse() * B
is exactly the same thing as A:toObjectSpace(B)
. Again, this corresponds exactly to the matrix inverse.
weld.Part0.CFrame*CFrame.new(-1,1,0)
This will be 1 stud left and one stud up of the first part in the weld. If you imagine the part 2x2x2 cube, it will be one of the corners.
CFrame.new( ... , mouse.Hit.p )
CFrame.new(from, to)
makes a CFrame positioned at from
and looking towards to
. This means we get a point looking from the point described above towards where the mouse is pointing.
* CFrame.Angles(math.pi/2,0,0);
This rotates the CFrame in place, tilting it 90 degrees down about it's X axis -- the 'front' is now facing down instead of forward.
Welds have a C0
and C1
which are Object Space to some arbitrary point in space. Usually it's easier to just have one part relative to the other, so you want one of them to be the same as that object space.
That is when you have C0
(or C1
) as the default CFrame -- CFrame.new()
.
desired_p1:inverse()*weld.Part0.CFrame
This lets us get a CFrame in the object space of the weld -- it's relative to where Part0 is, (from the previous step) is also where our weld is.
However, I think it ought to be the other way around, probably the rest of it was made to work with this order.
This effectively let's you use World-Space up until the final point when you want to put it into the weld, which makes it very easy to manage.