Cookbook (Chapter 2): Difference between revisions

From Legacy Roblox Wiki
Jump to navigationJump to search
>Gordonrox24
→‎CFrame: links
>JulienDethurens
 
(22 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{Map|Cookbook}}
==Positioning Types==
==Positioning Types==
There are 3 types of positioning you can use (technically there are 5).  The first is called Vector3, this is the simple type of positioning that allows one to move rendered parts around the 3 dimensional plane.  The second type of positioning is called CFrame (it stands for coordinate frame).  The CFrame parts to have rotation and more complex positioning in the 3 dimensional plane.  The third type of positioning is called UDim2.  This type of positioning allows for GUI (graphic user interfaces) to be moved around the 2 dimensional plane (also called the cartesian coordinate system).
There are 3 types of positioning you can use (technically there are 5).  The first is called [[Vector3]], this is the simple type of positioning that allows one to move rendered parts around the 3 dimensional plane.  The second type of positioning is called <abbr title="Coordinate Frame">CFrame</abbr>.  The [[CFrame]] parts can have rotation and more complex positioning in the 3 dimensional plane.  The third type of positioning is called [[UDim2]].  This type of positioning allows for <abbr title="Graphic User Interface">GUI</abbr>s to be moved around the 2 dimensional plane (also called the cartesian coordinate system).
   
   
===Vector3===
===Vector3===
The Vector3 type (as the name implies) has three components.  Since we are dealing with 3 dimensions, these components are the X, Y, and Z axes (left and right, up and down, forward and backward).  To create a new Vector3 you must use the Vector3.new function.
The [[Vector3]] type (as the name implies) has three components.  Since we are dealing with 3 dimensions, these components are the X, Y, and Z axes (left and right, up and down, forward and backward).  To create a new Vector3 you must use the Vector3.new function.


local pos = Vector3.new(1, 2, 3)
{{lua|=local pos = Vector3.new(1, 2, 3)}}
   
   
In the following code we create a new Vector3 with an X of 1, a Y of 2, and a Z of 3.  The center of your level (also called the origin) would be at point (0, 0, 0).  You can also do math on Vector3  values.
In the following code we create a new Vector3 with an X of 1, a Y of 2, and a Z of 3.  The center of your level (also called the origin) would be at point (0, 0, 0).  You can also do math on Vector3  values.
   
   
local pos = Vector3.new(0, 1, 0) + Vector3.new(1, 0, 1)
{{lua|=local pos = Vector3.new(0, 1, 0) + Vector3.new(1, 0, 1)}}
   
   
In that piece of code “pos” would be equal to a Vector3 of (1, 1, 1).  You can also subtract, multiply and divide [[Vector3#Operators|Vector3 values]].  You can index individual components of a Vector3 also.
In that piece of code “pos” would be equal to a Vector3 of (1, 1, 1).  You can also subtract, multiply and divide [[Vector3#Operators|Vector3 values]].  You can index individual components of a Vector3 also.
   
   
local xVal = Vector3.new(25, 0, 7).x
{{lua|=local xVal = Vector3.new(25, 0, 7).x}}
   
   
In that piece of code, “xVal” would be equal to 25 since that Vector3 had an X value of 25.  You can access the Y, and Z values similarly.  These components are read only, so you cannot change the value of a Vector3 like that, however you can construct a new Vector3 using the components of an old one.
In that piece of code, “xVal” would be equal to 25 since that Vector3 had an X value of 25.  You can access the Y, and Z values similarly.  These components are read only, so you cannot change the value of a Vector3 like that, however you can construct a new Vector3 using the components of an old one.
   
   
There are two other important Vector3 properties. The first is Vector3.magnitude, this returns the length of the Vector.  If you’ve ever studied Vectors you know that a Vector has a direction, and a magnitude (length).  This returns that length of the Vector, this is useful for calculating distance which will be discussed later on.  The Vector3 also has a Vector3.unit property which will normalize the Vector and just return its direction.
There are two other important Vector3 properties. The first is Vector3.magnitude, this returns the length of the Vector.  If you've ever studied Vectors you know that a Vector has a direction, and a magnitude (length).  This returns that length of the Vector, this is useful for calculating distance which will be discussed later on.  The Vector3 also has a Vector3.unit property which will normalize the Vector and just return its direction.


===CFrame===
===CFrame===
The CFrame type is used for positioning parts and rotation.  It includes a lot of advanced methods and properties to do so.  A simple CFrame value can be created with the CFrame.new function.
The [[CFrame]] type is used for positioning parts and rotation.  It includes a lot of advanced methods and properties to do so.  A simple CFrame value can be created with the CFrame.new function.
   
   
local cf = CFrame.new(Vector3.new(1, 1, 1))
{{lua|=local cf = CFrame.new(Vector3.new(1, 1, 1))}}
   
   
This will set “cf” to a new CFrame value whose position is equal to the Vector3 that is was given.  We can also set a direct for the CFrame to be looking at.
This will set “cf” to a new CFrame value whose position is equal to the Vector3 that is was given.  We can also set a direct for the CFrame to be looking at.
   
   
local cf = CFrame.new(Vector3.new(0, 0, 0), Vector3.new(10, 2, 6))
{{lua|=local cf = CFrame.new(Vector3.new(0, 0, 0), Vector3.new(10, 2, 6))}}
   
   
In that piece of code “cf” would be set to a CFrame value whose position is at the origin and is looking at the point (10, 2, 6).  CFrame values can be operated on similarly to the operators of [[Vector3#Operators|Vector3 values]].  In order to get the components of a CFrame value, you use the CFrame:components() method (there is shorthand access to position properties of a CFrame discussed later).
In that piece of code “cf” would be set to a CFrame value whose position is at the origin and is looking at the point (10, 2, 6).  CFrame values can be operated on similarly to the operators of [[Vector3#Operators|Vector3 values]].  In order to get the components of a CFrame value, you use the CFrame:components() method (there is shorthand access to position properties of a CFrame discussed later).
   
   
local x = CFrame.new(Vector3.new(10, 20, 30)):components()
{{lua|=local x = CFrame.new(Vector3.new(10, 20, 30)):components()}}
   
   
This will set “x” to 10.  There are many more components to a CFrame value than to a Vector3 value.  You can use a Vector to control rotation (as seen in the first example), you can use a quaternion, or you can use a rotational matrix.  These methods can be complex so there is a method inside of the CFrame that helps control rotation.  This is the CFrame.Angles function.
This will set “x” to 10.  There are many more components to a CFrame value than to a Vector3 value.  You can use a Vector to control rotation (as seen in the first example), you can use a quaternion, or you can use a rotational matrix.  These methods can be complex so there is a method inside of the CFrame that helps control rotation.  This is the CFrame.Angles function.
   
   
local cf = CFrame.new(1, 2, 3) * CFrame.Angles(0, math.pi, 0)
{{lua|=local cf = CFrame.new(1, 2, 3) * CFrame.Angles(0, math.pi, 0)}}
   
   
Here I used the shorthand notation for creating a CFrame (instead of inputted a Vector3 with the coordinates, I just put in the coordinates right to CFrame.new).  This would set “cf” to a CFrame value at position (1, 2, 3) rotated 180 degrees on the Y axis.  ROBLOX uses radians not degrees, so if you are more comfortable with degrees you could use the math.rad function.
Here I used the shorthand notation for creating a CFrame (instead of inputted a Vector3 with the coordinates, I just put in the coordinates right to CFrame.new).  This would set “cf” to a CFrame value at position (1, 2, 3) rotated 180 degrees on the Y axis.  ROBLOX uses radians not degrees, so if you are more comfortable with degrees you could use the math.rad function.
   
   
local cf = CFrame.new(1, 2, 3) * CFrame.Angles(0, math.rad(180), 0)
{{lua|=local cf = CFrame.new(1, 2, 3) * CFrame.Angles(0, math.rad(180), 0)}}
   
   
This would give the exact same rotation since math.pi and math.rad(180) are equal.  CFrames also have some helpful properties.  You can return the 3D position of a CFrame (in Vector3 form) by using the CFrame.p property.  You can also get the individual axes that the position is on, so CFrame.x is equal to CFrame.p.x.  You can also get the direction of a CFrame by doing CFrame.lookVector.  This is just a general overview of the CFrame, please read the [[CFrame]] documentation for more information.
This would give the exact same rotation since math.pi and math.rad(180) are equal.  CFrames also have some helpful properties.  You can return the 3D position of a CFrame (in Vector3 form) by using the CFrame.p property.  You can also get the individual axes that the position is on, so CFrame.x is equal to CFrame.p.x.  You can also get the direction of a CFrame by doing CFrame.lookVector.  This is just a general overview of the CFrame, please read the [[CFrame]] documentation for more information.


===UDim2===
===UDim2===
Later on we will be discussing GUI in depth so don’t worry if you don’t know what they are, just know that they are in the 2D coordinate field.  The UDim2 positioning system is used to position them.  There are four parts to a UDim2, the x-scale, x-offset, y-scale, and y-offset.  The first two control the X coordinate in different way, and the same goes for the last two.  The scale types control position relative to the screen size.  For example, with the x-scale, if its 0, then it will be at the left side of the screen, if its 1, then it will be at the right side.  The offset ones use pixels to define position.
Later on we will be discussing <abbr title="Graphic User Interface">GUI</abbr>s in depth so don't worry if you don't know what they are, just know that they are in the 2D coordinate field.  The [[UDim2]] positioning system is used to position them.  There are four parts to a UDim2, the x-scale, x-offset, y-scale, and y-offset.  The first two control the X coordinate in different way, and the same goes for the last two.  The scale types control position relative to the screen size.  For example, with the x-scale, if its 0, then it will be at the left side of the screen, if its 1, then it will be at the right side.  The offset ones use pixels to define position.
   
   
local pos = UDim2.new(.5, 0, .5, 0)
{{lua|=local pos = UDim2.new(.5, 0, .5, 0)}}
   
   
This UDim2 would be located in the center of the screen no matter what the resolution of the user’s screen is.  To index them, you would use UDim2.X, which would return a UDim.  Then from this you can index UDim.Scale, or UDim.Offset.
This UDim2 would be located in the center of the screen no matter what the resolution of the user's screen is.  To index them, you would use UDim2.X, which would return a UDim.  Then from this you can index UDim.Scale, or UDim.Offset.


==Simple Part Positioning==
==Simple Part Positioning==
Line 55: Line 56:
===Solution===
===Solution===
Use Vector3 values to alter the Position and Size properties.
Use Vector3 values to alter the Position and Size properties.
{{Example|<pre>
{{Example|{{lua|=
local part = Instance.new(‘Part’)
local part = Instance.new('Part')
part.Parent = game.Workspace
part.Parent = Workspace
part.Size = Vector3.new(100, 1, 100)
part.Size = Vector3.new(100, 1, 100)
part.Position = Vector3.new(0, 0, 0)
part.Position = Vector3.new(0, 0, 0)
part.Anchored = true
part.Anchored = true
</pre>}}
}}}}


===Discussion===
===Discussion===
Here we created a new part, and parented it to the Workspace.  Then we change its size to be 100 as the length, 1 as the height, and 100 as the width.  We also change its position to be at the origin and then anchor it.
Here we created a new part, and parented it to the Workspace.  Then we change its size to be 100 as the length, 1 as the height, and 100 as the width.  We also change its position to be at the origin and then anchor it.
   
   
Do note that Vector3 is measured in studs (if you’ve ever seen a base plate with little circles on it, each one of these circles is a stud).
Do note that Vector3 is measured in studs (if you've ever seen a base plate with little circles on it, each one of these circles is a stud).


==Overlapping Positioning==
==Overlapping Positioning==
===Problem===
===Problem===
You want to position a part so that if another part is occupying the same space, the part you’re positioning will move up until it no longer occupying the same space.
You want to position a part so that if another part is occupying the same space, the part you're positioning will move up until it no longer occupying the same space.
   
   
===Solution===
===Solution===
Use Vector3 values to position it.
Use Vector3 values to position it.
{{Example|<pre>
{{Example|{{lua|=
local part = Instance.new(‘Part’)
local part = Instance.new('Part')
part.Parent = game.Workspace
part.Parent = Workspace
part.Anchored = true
part.Anchored = true
part.Position = Vector3.new(0, 0, 0)
part.Position = Vector3.new(0, 0, 0)
local part2 = part:clone()
local part2 = part:clone()
part2.Parent = game.Workspace
part2.Parent = Workspace
part2.Anchored = false
part2.Anchored = false
</pre>}}
}}}}


===Discussion===
===Discussion===
Line 94: Line 95:
   
   
===Solution===
===Solution===
Set a part’s CFrame property to a new CFrame value.
Set a part's CFrame property to a new CFrame value.
{{Example|<pre>
{{Example|{{lua|=
local part = Instance.new(‘Part’)
local part = Instance.new('Part')
part.Parent = game.Workspace
part.Parent = Workspace
part.Anchored = true
part.Anchored = true
part.CFrame = CFrame.new(0, 0, 0)
part.CFrame = CFrame.new(0, 0, 0)
</pre>}}
}}}}


===Discussion===
===Discussion===
Line 113: Line 114:
===Solution===
===Solution===
Use the second CFrame argument to rotate in that direction.
Use the second CFrame argument to rotate in that direction.
{{Example|<pre>
{{Example|{{lua|=
local part = Instance.new(‘Part’)
local part = Instance.new('Part')
part.Parent = game.Workspace
part.Parent = Workspace
part.Anchored = true
part.Anchored = true
part.CFrame = CFrame.new(Vector3.new(0, 0, 0), game.Workspace.pointAtPart.Position)
part.CFrame = CFrame.new(Vector3.new(0, 0, 0), Workspace.pointAtPart.Position)
</pre>}}
}}}}


===Discussion===
===Discussion===
We’re basically setting part.CFrame to a new CFrame which is at the position of (0, 0, 0), and is rotated at the part “pointAtPart”.  We use pointAtPart.Position because we want to point at a Vector3 value which is returned by the Position property or CFrame.p.
We're basically setting part.CFrame to a new CFrame which is at the position of (0, 0, 0), and is rotated at the part “pointAtPart”.  We use pointAtPart.Position because we want to point at a Vector3 value which is returned by the Position property or CFrame.p.


==Rotating in Radians==
==Rotating in Radians==
Line 129: Line 130:
===Solution===
===Solution===
Use the CFrame.Angles function and multiply it by the CFrame position.
Use the CFrame.Angles function and multiply it by the CFrame position.
{{Example|<pre>
{{Example|{{lua|=
local part = Instance.new(‘Part’)
local part = Instance.new('Part')
part.Parent = game.Workspace
part.Parent = Workspace
part.Anchored = true
part.Anchored = true
part.CFrame = part.CFrame * CFrame.Angles(0, math.pi, 0)
part.CFrame = part.CFrame * CFrame.Angles(0, math.pi, 0)
</pre>}}
}}}}


===Discussion===
===Discussion===
To get a rotated CFrame we take the position and multiply it by an Angle component.  We get this by calling the CFrame.Angles function.  Here we just want to rotate the part, so we want the same position so we just use part.CFrame and multiply it by CFrame.Angles(0, math.pi, 0).  We’re rotating in radians here on the Y axis by math.pi which is equal to 180 degrees.  Not familiar with radians?  Don’t fear, read the next recipe!
To get a rotated CFrame we take the position and multiply it by an Angle component.  We get this by calling the CFrame.Angles function.  Here we just want to rotate the part, so we want the same position so we just use part.CFrame and multiply it by CFrame.Angles(0, math.pi, 0).  We're rotating in radians here on the Y axis by math.pi which is equal to 180 degrees.  Not familiar with radians?  Don't fear, read the next recipe!


==Rotating in Degrees==
==Rotating in Degrees==
Line 145: Line 146:
===Solution===
===Solution===
Use the CFrame.Angles function and multiply it by the CFrame position using the math.rad function to convert degrees to radians.
Use the CFrame.Angles function and multiply it by the CFrame position using the math.rad function to convert degrees to radians.
{{Example|<pre>
{{Example|{{lua|=
local part = Instance.new(‘Part’)
local part = Instance.new('Part')
part.Parent = game.Workspace
part.Parent = Workspace
part.Anchored = true
part.Anchored = true
part.CFrame = part.CFrame * CFrame.Angles(0, math.rad(5), 0)
part.CFrame = part.CFrame * CFrame.Angles(0, math.rad(5), 0)
</pre>}}
}}}}




Line 156: Line 157:
We set part.CFrame to the same position part.CFrame and multiply it by CFrame.Angles but with math.rad(5) as the Y axis rotation.  The math.rad function converts degrees to radians.  So in this case we are converting 5 degrees to radians and passing it to CFrame.Angles.
We set part.CFrame to the same position part.CFrame and multiply it by CFrame.Angles but with math.rad(5) as the Y axis rotation.  The math.rad function converts degrees to radians.  So in this case we are converting 5 degrees to radians and passing it to CFrame.Angles.
   
   
Other times you may see CFrame.fromEulerAnglesXYZ.  The function we’ve been using (CFrame.Angles) is just a shortcut function for CFrame.fromEulerAnglesXYZ.  You shouldn’t use the old name (its much too long), but if you see it in code you will no longer be confused.
Other times you may see CFrame.fromEulerAnglesXYZ.  The function we've been using (CFrame.Angles) is just a shortcut function for CFrame.fromEulerAnglesXYZ.  You shouldn't use the old name (its much too long), but if you see it in code you will no longer be confused.


==Relative Positioning==
==Relative Positioning==
Line 164: Line 165:
===Solution===
===Solution===
Use the CFrame:toWorldSpace method.
Use the CFrame:toWorldSpace method.
{{Example|<pre>
{{Example|{{lua|=
local part = Instance.new(‘Part’)
local part = Instance.new('Part')
part.Parent = game.Workspace
part.Parent = Workspace
part.Anchored = true
part.Anchored = true
part.CFrame = CFrame.new(0, 5, 0):toWorldSpace(game.Workspace.Part)
part.CFrame = CFrame.new(0, 5, 0):toWorldSpace(Workspace.Part)
</pre>}}
}}}}
   
   
===Discussion===
===Discussion===
In this code we set a newly created part’s CFrame to be 5 studs higher than then CFrame of game.Workspace.Part.  Say that game.Workspace.Part is in the center of the map.  We have another position that’s (0, 5, 0).  It will be located five studs above game.Workspace.Part.  However game.Workspace.Part is not in the center, its somewhere else.  When we call CFrame:toWorldSpace we use what game.Workspace.Part, but create a new CFrame that keeps the relativity of CFrame.new(0, 5, 0) to game.Workspace.Part.  Resulting in a new CFrame which is five studs higher than game.Workspace.Part.
In this code we set a newly created part's CFrame to be 5 studs higher than then CFrame of Workspace.Part.  Say that Workspace.Part is in the center of the map.  We have another position that's (0, 5, 0).  It will be located five studs above Workspace.Part.  However Workspace.Part is not in the center, its somewhere else.  When we call CFrame:toWorldSpace we use what Workspace.Part, but create a new CFrame that keeps the relativity of CFrame.new(0, 5, 0) to Workspace.Part.  Resulting in a new CFrame which is five studs higher than Workspace.Part.


==Getting Relative Position==
==Getting Relative Position==
Line 180: Line 181:
===Solution===
===Solution===
Use the CFrame:toObjectSpace method.
Use the CFrame:toObjectSpace method.
{{Example|<pre>
{{Example|{{lua|=
game.Workspace.Part.CFrame:toObjectSpace(game.Workspace.Part2.CFrame)
Workspace.Part.CFrame:toObjectSpace(Workspace.Part2.CFrame)
</pre>}}
}}}}


===Discussion===
===Discussion===
We want to find how “Part2” is positioned relative to “Part”.  We use “Part” as the origin and convert the CFrame of “Part2” to be relative to the CFrame of “Part”.  This leaves us with how “Part2” is relative to “Part”.  What can we do with this information?  We can find the distance between the two like so:
We want to find how “Part2” is positioned relative to “Part”.  We use “Part” as the origin and convert the CFrame of “Part2” to be relative to the CFrame of “Part”.  This leaves us with how “Part2” is relative to “Part”.  What can we do with this information?  We can find the distance between the two like so:
   
   
game.Workspace.Part.CFrame:toObjectSpace(game.Workspace.Part2.CFrame).p.magnitude
Workspace.Part.CFrame:toObjectSpace(Workspace.Part2.CFrame).p.magnitude
   
   
We use the position component of the CFrame and get its length (using the magnitude property).  Since we’re using relative positioning we are left we just how the two are related.  We could also get the length between the two like so:
We use the position component of the CFrame and get its length (using the magnitude property).  Since we're using relative positioning we are left we just how the two are related.  We could also get the length between the two like so:
   
   
(game.Workspace.Part.Position  - game.Workspace.Part2.position).magnitude
(Workspace.Part.Position  - Workspace.Part2.position).magnitude
   
   
Using subtraction we can also get relative positioning.
Using subtraction we can also get relative positioning.
Line 201: Line 202:
===Solution===
===Solution===
Use the CFrame.new function.
Use the CFrame.new function.
{{Example|<pre>
{{Example|{{lua|=
workspace.Part.CFrame = CFrame.new(0, 0, 0, 1, 0, 0, 0, math.cos(90), math.sin(-90), 0, math.sin(90), math.cos(90))
Workspace.Part.CFrame = CFrame.new(0, 0, 0, 1, 0, 0, 0, math.cos(90), math.sin(-90), 0, math.sin(90), math.cos(90))
</pre>}}
}}}}
 
===Discussion===
===Discussion===
Explaining how the rotational matrix works in beyond the scope of this book.  CFrame.new will take the first 3 arguments as the position (typical, X, Y, Z), and then the next 9 arguments are the components of the rotational matrix.
Explaining how the rotational matrix works is beyond the scope of this book.  CFrame.new will take the first 3 arguments as the position (typical, X, Y, Z), and then the next 9 arguments are the components of the rotational matrix.


==Using Lerp==
==Using Lerp==
Line 214: Line 215:
===Solution===
===Solution===
Use the Vector3:Lerp method with an alpha of ½.
Use the Vector3:Lerp method with an alpha of ½.
{{Example|<pre>
{{Example|{{lua|=
local part = Instance.new(‘Part’)
local part = Instance.new('Part')
part.Parent = game.Worksapce
part.Parent = game.Worksapce
part.Anchored = true
part.Anchored = true
part.Position = game.Workspace.Part.Position:Lerp(game.Workspace.Part2.Position, .5)
part.Position = Workspace.Part.Position:Lerp(Workspace.Part2.Position, .5)
</pre>}}
}}}}


===Discussion===
===Discussion===
Line 230: Line 231:
===Solution===
===Solution===
Use the UDim2.new function and use the Offsets.
Use the UDim2.new function and use the Offsets.
{{Example|<pre>
{{Example|{{lua|=
local frame = Instance.new(‘Frame’)
local frame = Instance.new('Frame')
frame.Position = UDim2.new(0, 50, 0, 50)
frame.Position = UDim2.new(0, 50, 0, 50)
</pre>}}
}}}}


===Discussion===
===Discussion===
Line 246: Line 247:
===Solution===
===Solution===
Use the UDim2.new function and use the Scales.
Use the UDim2.new function and use the Scales.
{{Example|<pre>
{{Example|{{lua|=
local frame = Instance.new(‘Frame’)
local frame = Instance.new('Frame')
frame.Size = UDim2.new(0, 100, 0, 100)
frame.Size = UDim2.new(0, 100, 0, 100)
frame.Position = UDim2.new(.5, -50, .5, -50)
frame.Position = UDim2.new(.5, -50, .5, -50)
</pre>}}
}}}}


===Discussion===
===Discussion===
Here we are setting the size of a Frame to be 100x100 pixels.  Next we set the Position to have a UDim2 which has an X and Y Scale component of ½ (the middle of the screen) and X and Y Offset components of -50.  The Scale components uses relative to the screen so 0 would be all the way to the left or top and 1 would be to the bottom or right.  Making that ½ on each axis would make it perfectly in the center.  Or would it?  Sizing occurs from the top left of the frame, so that would make the top right corner of the frame be the center.  Most likely we want the frame itself to be centered.
Here we are setting the size of a Frame to be 100x100 pixels.  Next we set the Position to have a UDim2 which has an X and Y Scale component of ½ (the middle of the screen) and X and Y Offset components of -50.  The Scale components uses relative to the screen so 0 would be all the way to the left or top and 1 would be to the bottom or right.  Making that ½ on each axis would make it perfectly in the center.  Or would it?  Sizing occurs from the top left of the frame, so that would make the top right corner of the frame be the center.  Most likely we want the frame itself to be centered.
   
   
To remedy this problem we set the Offset components of the position to be negative ½ of the size of each axis.  Think of it this way, we want to get the center of the frame in the center of the screen.  The center of the frame would be ½ of each axis.  Now we have the frame’s top left hand corner positioned in the center of the screen.  We must use subtraction in order to oriented it into the center so we take the negative of that.
To remedy this problem we set the Offset components of the position to be negative ½ of the size of each axis.  Think of it this way, we want to get the center of the frame in the center of the screen.  The center of the frame would be ½ of each axis.  Now we have the frame's top left hand corner positioned in the center of the screen.  We must use subtraction in order to oriented it into the center so we take the negative of that.
 
[[Cookbook (Chapter 3)|Continue on to Chapter 3, GUI]]
 
[[Category:Cookbook]]

Latest revision as of 23:21, 27 February 2012

Positioning Types

There are 3 types of positioning you can use (technically there are 5). The first is called Vector3, this is the simple type of positioning that allows one to move rendered parts around the 3 dimensional plane. The second type of positioning is called CFrame. The CFrame parts can have rotation and more complex positioning in the 3 dimensional plane. The third type of positioning is called UDim2. This type of positioning allows for GUIs to be moved around the 2 dimensional plane (also called the cartesian coordinate system).

Vector3

The Vector3 type (as the name implies) has three components. Since we are dealing with 3 dimensions, these components are the X, Y, and Z axes (left and right, up and down, forward and backward). To create a new Vector3 you must use the Vector3.new function.

local pos = Vector3.new(1, 2, 3)

In the following code we create a new Vector3 with an X of 1, a Y of 2, and a Z of 3. The center of your level (also called the origin) would be at point (0, 0, 0). You can also do math on Vector3 values.

local pos = Vector3.new(0, 1, 0) + Vector3.new(1, 0, 1)

In that piece of code “pos” would be equal to a Vector3 of (1, 1, 1). You can also subtract, multiply and divide Vector3 values. You can index individual components of a Vector3 also.

local xVal = Vector3.new(25, 0, 7).x

In that piece of code, “xVal” would be equal to 25 since that Vector3 had an X value of 25. You can access the Y, and Z values similarly. These components are read only, so you cannot change the value of a Vector3 like that, however you can construct a new Vector3 using the components of an old one.

There are two other important Vector3 properties. The first is Vector3.magnitude, this returns the length of the Vector. If you've ever studied Vectors you know that a Vector has a direction, and a magnitude (length). This returns that length of the Vector, this is useful for calculating distance which will be discussed later on. The Vector3 also has a Vector3.unit property which will normalize the Vector and just return its direction.

CFrame

The CFrame type is used for positioning parts and rotation. It includes a lot of advanced methods and properties to do so. A simple CFrame value can be created with the CFrame.new function.

local cf = CFrame.new(Vector3.new(1, 1, 1))

This will set “cf” to a new CFrame value whose position is equal to the Vector3 that is was given. We can also set a direct for the CFrame to be looking at.

local cf = CFrame.new(Vector3.new(0, 0, 0), Vector3.new(10, 2, 6))

In that piece of code “cf” would be set to a CFrame value whose position is at the origin and is looking at the point (10, 2, 6). CFrame values can be operated on similarly to the operators of Vector3 values. In order to get the components of a CFrame value, you use the CFrame:components() method (there is shorthand access to position properties of a CFrame discussed later).

local x = CFrame.new(Vector3.new(10, 20, 30)):components()

This will set “x” to 10. There are many more components to a CFrame value than to a Vector3 value. You can use a Vector to control rotation (as seen in the first example), you can use a quaternion, or you can use a rotational matrix. These methods can be complex so there is a method inside of the CFrame that helps control rotation. This is the CFrame.Angles function.

local cf = CFrame.new(1, 2, 3) * CFrame.Angles(0, math.pi, 0)

Here I used the shorthand notation for creating a CFrame (instead of inputted a Vector3 with the coordinates, I just put in the coordinates right to CFrame.new). This would set “cf” to a CFrame value at position (1, 2, 3) rotated 180 degrees on the Y axis. ROBLOX uses radians not degrees, so if you are more comfortable with degrees you could use the math.rad function.

local cf = CFrame.new(1, 2, 3) * CFrame.Angles(0, math.rad(180), 0)

This would give the exact same rotation since math.pi and math.rad(180) are equal. CFrames also have some helpful properties. You can return the 3D position of a CFrame (in Vector3 form) by using the CFrame.p property. You can also get the individual axes that the position is on, so CFrame.x is equal to CFrame.p.x. You can also get the direction of a CFrame by doing CFrame.lookVector. This is just a general overview of the CFrame, please read the CFrame documentation for more information.

UDim2

Later on we will be discussing GUIs in depth so don't worry if you don't know what they are, just know that they are in the 2D coordinate field. The UDim2 positioning system is used to position them. There are four parts to a UDim2, the x-scale, x-offset, y-scale, and y-offset. The first two control the X coordinate in different way, and the same goes for the last two. The scale types control position relative to the screen size. For example, with the x-scale, if its 0, then it will be at the left side of the screen, if its 1, then it will be at the right side. The offset ones use pixels to define position.

local pos = UDim2.new(.5, 0, .5, 0)

This UDim2 would be located in the center of the screen no matter what the resolution of the user's screen is. To index them, you would use UDim2.X, which would return a UDim. Then from this you can index UDim.Scale, or UDim.Offset.

Simple Part Positioning

Problem

You want to position a part at the origin and re-size it.

Solution

Use Vector3 values to alter the Position and Size properties.

Example
local part = Instance.new('Part')
part.Parent = Workspace
part.Size = Vector3.new(100, 1, 100)
part.Position = Vector3.new(0, 0, 0)
part.Anchored = true


Discussion

Here we created a new part, and parented it to the Workspace. Then we change its size to be 100 as the length, 1 as the height, and 100 as the width. We also change its position to be at the origin and then anchor it.

Do note that Vector3 is measured in studs (if you've ever seen a base plate with little circles on it, each one of these circles is a stud).

Overlapping Positioning

Problem

You want to position a part so that if another part is occupying the same space, the part you're positioning will move up until it no longer occupying the same space.

Solution

Use Vector3 values to position it.

Example
local part = Instance.new('Part')
part.Parent = Workspace
part.Anchored = true
part.Position = Vector3.new(0, 0, 0)
local part2 = part:clone()
part2.Parent = Workspace
part2.Anchored = false


Discussion

We create a part like normal, parent it to the Workspace and then anchor it. We then change its position to the origin. We then create a new variable “part2” and set it to be a clone of the first part using the clone method. By default cloned objects are not parented to the Workspace. We then set Anchored on this new cloned part to false.

By settings Anchored to false, we allow the part to move out of place. If you have two parts that are overlapping and you allow it to move, then it will move up and out of the way. Otherwise, if both parts are Anchored, then they will be occupying the same space.

Simple CFrame Positioning

Problem

You want to position a part at the origin using its CFrame.

Solution

Set a part's CFrame property to a new CFrame value.

Example
local part = Instance.new('Part')
part.Parent = Workspace
part.Anchored = true
part.CFrame = CFrame.new(0, 0, 0)


Discussion

Here we set part.CFrame to a new CFrame with the position (0, 0, 0) which is the origin. An alternative method to create the same CFrame value would be as follows.

part.CFrame = CFrame.new(Vector3.new(0, 0, 0))

Rotating Toward Another Position

Problem

You want to rotate a part toward another part.

Solution

Use the second CFrame argument to rotate in that direction.

Example
local part = Instance.new('Part')
part.Parent = Workspace
part.Anchored = true
part.CFrame = CFrame.new(Vector3.new(0, 0, 0), Workspace.pointAtPart.Position)


Discussion

We're basically setting part.CFrame to a new CFrame which is at the position of (0, 0, 0), and is rotated at the part “pointAtPart”. We use pointAtPart.Position because we want to point at a Vector3 value which is returned by the Position property or CFrame.p.

Rotating in Radians

Problem

You want to rotate a part in radians.

Solution

Use the CFrame.Angles function and multiply it by the CFrame position.

Example
local part = Instance.new('Part')
part.Parent = Workspace
part.Anchored = true
part.CFrame = part.CFrame * CFrame.Angles(0, math.pi, 0)


Discussion

To get a rotated CFrame we take the position and multiply it by an Angle component. We get this by calling the CFrame.Angles function. Here we just want to rotate the part, so we want the same position so we just use part.CFrame and multiply it by CFrame.Angles(0, math.pi, 0). We're rotating in radians here on the Y axis by math.pi which is equal to 180 degrees. Not familiar with radians? Don't fear, read the next recipe!

Rotating in Degrees

Problem

You want to rotate a part in degrees.

Solution

Use the CFrame.Angles function and multiply it by the CFrame position using the math.rad function to convert degrees to radians.

Example
local part = Instance.new('Part')
part.Parent = Workspace
part.Anchored = true
part.CFrame = part.CFrame * CFrame.Angles(0, math.rad(5), 0)


Discussion

We set part.CFrame to the same position part.CFrame and multiply it by CFrame.Angles but with math.rad(5) as the Y axis rotation. The math.rad function converts degrees to radians. So in this case we are converting 5 degrees to radians and passing it to CFrame.Angles.

Other times you may see CFrame.fromEulerAnglesXYZ. The function we've been using (CFrame.Angles) is just a shortcut function for CFrame.fromEulerAnglesXYZ. You shouldn't use the old name (its much too long), but if you see it in code you will no longer be confused.

Relative Positioning

Problem

You want to position a part relative to another part.

Solution

Use the CFrame:toWorldSpace method.

Example
local part = Instance.new('Part')
part.Parent = Workspace
part.Anchored = true
part.CFrame = CFrame.new(0, 5, 0):toWorldSpace(Workspace.Part)


Discussion

In this code we set a newly created part's CFrame to be 5 studs higher than then CFrame of Workspace.Part. Say that Workspace.Part is in the center of the map. We have another position that's (0, 5, 0). It will be located five studs above Workspace.Part. However Workspace.Part is not in the center, its somewhere else. When we call CFrame:toWorldSpace we use what Workspace.Part, but create a new CFrame that keeps the relativity of CFrame.new(0, 5, 0) to Workspace.Part. Resulting in a new CFrame which is five studs higher than Workspace.Part.

Getting Relative Position

Problem

You want to know where something is relative to where something else is.

Solution

Use the CFrame:toObjectSpace method.

Example
Workspace.Part.CFrame:toObjectSpace(Workspace.Part2.CFrame)


Discussion

We want to find how “Part2” is positioned relative to “Part”. We use “Part” as the origin and convert the CFrame of “Part2” to be relative to the CFrame of “Part”. This leaves us with how “Part2” is relative to “Part”. What can we do with this information? We can find the distance between the two like so:

Workspace.Part.CFrame:toObjectSpace(Workspace.Part2.CFrame).p.magnitude

We use the position component of the CFrame and get its length (using the magnitude property). Since we're using relative positioning we are left we just how the two are related. We could also get the length between the two like so:

(Workspace.Part.Position - Workspace.Part2.position).magnitude

Using subtraction we can also get relative positioning.

Using the Rotational Matrix

Problem

You want to use the rotational matrix to do rotations.

Solution

Use the CFrame.new function.

Example
Workspace.Part.CFrame = CFrame.new(0, 0, 0, 1, 0, 0, 0, math.cos(90), math.sin(-90), 0, math.sin(90), math.cos(90))


Discussion

Explaining how the rotational matrix works is beyond the scope of this book. CFrame.new will take the first 3 arguments as the position (typical, X, Y, Z), and then the next 9 arguments are the components of the rotational matrix.

Using Lerp

Problem

You want to position a part halfway between two other parts.

Solution

Use the Vector3:Lerp method with an alpha of ½.

Example
local part = Instance.new('Part')
part.Parent = game.Worksapce
part.Anchored = true
part.Position = Workspace.Part.Position:Lerp(Workspace.Part2.Position, .5)


Discussion

The Lerp function will take two vectors and an alpha (the last argument, a number between 0 and 1) and according to the alpha will create a new vector between the two other positions. So if the alpha is .5 (or one half) it will create a Vector halfway between the two other vectors (in this case “Part” and “Part2”).

Simple GUI Positioning

Problem

You want to position a GUI 50 pixels down and 50 pixels to the right.

Solution

Use the UDim2.new function and use the Offsets.

Example
local frame = Instance.new('Frame')
frame.Position = UDim2.new(0, 50, 0, 50)


Discussion

First and foremost, its important to note that the GUI code examples following will not produce any visible result, a future chapter will cover GUI in more depth, this will just be an introduction to positioning them.

We use UDim2 with 50 for the XOffset and YOffset components. This will move it down 50 pixels and to the right 50 pixels from the upper left hand side of the screen.

Centering GUI

Problem

You want to position a GUI in the center of the screen.

Solution

Use the UDim2.new function and use the Scales.

Example
local frame = Instance.new('Frame')
frame.Size = UDim2.new(0, 100, 0, 100)
frame.Position = UDim2.new(.5, -50, .5, -50)


Discussion

Here we are setting the size of a Frame to be 100x100 pixels. Next we set the Position to have a UDim2 which has an X and Y Scale component of ½ (the middle of the screen) and X and Y Offset components of -50. The Scale components uses relative to the screen so 0 would be all the way to the left or top and 1 would be to the bottom or right. Making that ½ on each axis would make it perfectly in the center. Or would it? Sizing occurs from the top left of the frame, so that would make the top right corner of the frame be the center. Most likely we want the frame itself to be centered.

To remedy this problem we set the Offset components of the position to be negative ½ of the size of each axis. Think of it this way, we want to get the center of the frame in the center of the screen. The center of the frame would be ½ of each axis. Now we have the frame's top left hand corner positioned in the center of the screen. We must use subtraction in order to oriented it into the center so we take the negative of that.

Continue on to Chapter 3, GUI