Cookbook (Chapter 2): Difference between revisions
>Camoy init Chapter 2 |
>Camoy init Chapter 2 |
(No difference)
|
Revision as of 22:41, 31 January 2011
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).
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 (http://wiki.roblox.com/index.php/Vector3#Operators). 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 (http://wiki.roblox.com/index.php/CFrame#Operators). 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 (http://wiki.roblox.com/index.php/CFrame).
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.
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.
local part = Instance.new(‘Part’) part.Parent = game.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.
local part = Instance.new(‘Part’) part.Parent = game.Workspace part.Anchored = true part.Position = Vector3.new(0, 0, 0) local part2 = part:clone() part2.Parent = game.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.
local part = Instance.new(‘Part’) part.Parent = game.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.
local part = Instance.new(‘Part’) part.Parent = game.Workspace part.Anchored = true part.CFrame = CFrame.new(Vector3.new(0, 0, 0), game.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.
local part = Instance.new(‘Part’) part.Parent = game.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.
local part = Instance.new(‘Part’) part.Parent = game.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.
local part = Instance.new(‘Part’) part.Parent = game.Workspace part.Anchored = true part.CFrame = CFrame.new(0, 5, 0):toWorldSpace(game.Workspace.Part)
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.
Getting Relative Position
Problem
You want to know where something is relative to where something else is.
Solution
Use the CFrame:toObjectSpace method.
game.Workspace.Part.CFrame:toObjectSpace(game.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:
game.Workspace.Part.CFrame:toObjectSpace(game.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:
(game.Workspace.Part.Position - game.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.
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 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.
Using Lerp
Problem
You want to position a part halfway between two other parts.
Solution
Use the Vector3:Lerp method with an alpha of ½.
local part = Instance.new(‘Part’) part.Parent = game.Worksapce part.Anchored = true part.Position = game.Workspace.Part.Position:Lerp(game.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.
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.
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.