In-Depth Scripting Guide: Difference between revisions
>JulienDethurens |
>JulienDethurens |
(No difference)
|
Revision as of 04:39, 6 April 2012
What You Need!
- ROBLOX Studio
- Explorer Tab - This tells you exactly where everything is.
- Properties Tab - This tells you all the things editable in an object.
- Output - A scripter's best friend. It tells you any mistakes (syntax, values, etc) found in a script, and where to find it.
- Command Bar (Optional) - Not really needed, but is a great way to test out one-lined wonders.
- Any script; new or old (Optional) - If you want an example script to look at, you can always pick one out of the toolbox.
Order of Operations; Script Style (VFC)
There is an order of which you should add your operations, just like in math. A mnemonic device for this order is "VFC", for "Variables, Functions, and Connections". A good script usually has itself in a neat and tidy order so that almost anyone can understand what the script does just by looking at it.
Variables
Usually in a script, there is a specific order in which you put your operations. First off, one of the most important things to put in the very beginning are variables. Variables are used to note objects that will be used a lot. If you like to be organized, you like to put things in models. Sometimes, that model chain can get pretty lengthy.
Example:
example = Workspace.Example
Notice how the variable has a name, which is "example." The name can be anything except numbers alone. If you have a name of just numbers and you use it in a script, you will end up with a syntax error. When defining a variable, you need to tell exactly where it is. The Explorer tab helps with this as there is always a little tab telling you that that object is a child of something. When typing the parental of the object you want, spell the parental(s) correctly. You do not need the function ":FindFirstChild()" when making variables.
Functions
Secondly, in many scripts, you will come across a function. A function is something that can be used repeatedly. Some functions are also used to shorten script length, and some are just there because someone didn't want to delete it. When I create functions, I create the ones without a connection first, and then I create the ones with a connection line afterwards. If I do it like this, I can use the non-connections in the ones with connections. After all the things inside, you always close a function with an "end" statement.
Example:
bin = script.Parent
function anchor(object)
object.Anchored = true
end
function onTouched(part)
anchor(part)
end
bin.Touched:connect(onTouched)
There is the one variable, not really needed but I need to stress its importance. In the first function, as in every function, the term "function" is first. It is correct if the term turns purple. After the term "function," the function needs to be named (in the example, there are two -- named "anchor" and "onTouched".) Do not use numbers as a name. It is better to spell out numbers in names, except in some occasions. Now, after the name, you'll see the word "object" in parentheses. You can rename it anything you want, except numbers, and you can use it for anything you want. It's like a function variable, you can use it to do other things and use it repeatedly with different terms. You can also add more variables to this by using commas. So, this example could have been made: "function anchor(object, statement)". In this function, though, it is anchoring the object no matter what. Finally, the "end" statement.
In the second function, the function has a connection line. It's the same as the first function, the "function" statement, the function name, and the variable. The difference is, the previous function anchors the so-called "part." The variable is defined as "part," which is in this case, the object being touched. Finally, the "end" statement as always.
Connection Lines
If you look in the above example, you will notice a connection line. A connection line does what it says, connects the function to something happening in a place. The layout for a connection line is very simple. Connection lines usually tell you that the script is doing and when.
Example:
bin = script.Parent
function anchor(object)
object.Anchored = true
end
function onTouched(part)
anchor(part)
end
bin.Touched:connect(onTouched) --this is called the "connection line"
Presuming this script is inside of a brick, it can therefore be touched. In the variables, the brick is called "bin." In the connection line, there is a specific order in which the line should be. It should be like this:
<Object>.<Event>:connect(<Function>)
The object "bin" (a brick) has an event called "Touched" which is being connected to the function "onTouched".
To find events for objects, check the Object Browser.
Basic Lua Keywords
Throughout Lua, you will find terms like 'if', 'local', and 'for'. In this section, I will teach you Basic Lua terms. I recommend, if you haven't, to read the Order of Operations section of this guide before going on with this one.
The if Statement
The if control structure takes one value directly after "if", and then the keyword "then", followed by a block of code that finishes with "end" (or an else statement). The if statement always executes the block of code after "then" unless the value given to it is either nil or false.
Example One
brick = Workspace:findFirstChild("Brick")
if brick then
print("The brick is here!")
end
In this snippet of code, the brick variable is defined as whatever is given by FindFirstChild. The if statement will check if the `brick` variable is neither nil nor false. If the FindFirstChild function returned a brick, then the if statement block of code will be run.
A common mistake when writing if-blocks is using a single equals sign instead of two. One equals sign is an assignment operator, not an equality operator. Use two equals signs when checking for equality!
Example Two
number = 0
while number < 10 do
wait(1)
number = number +1
if number > 5 then
print("Number Greater Than 5!")
end
end
On the first line, "number" is 0. The next step is a 'while true do' loop. It waits one second then "number" will increase by one. Then there is the 'if' statement. It is now asking if "number" is greater than 5. If "number" is greater than 5, it will print, "Number Greater Than 5!" If it isn't greater than 5, then it will just skip it and repeat the loop. Once "number" turns to 11, the loop will end. This also goes with connection functions.
TIP: When using 'if' statements, use the proper Operations of comparison.
The 'else' Statement
Say you have an 'if' function, but it has false or nil inside. That's when the 'else' kicks in. It does the function of the else onward to the end statement.
Example:
if Workspace == game.Lighting then
print("No way!")
else
print("Whew. That was close.")
end
Well, there's the 'if' statement's condition, which returns false. It then goes to the 'else' statement and executes to the end statement.
The 'elseif' Statement
'Elseif' is not an 'if' function. So what is the difference between 'elseif' and 'else if'? 'Elseif' is counted as an 'else' with a requirement for it to be run, and doesn't need an end. On the other hand, 'else if' is comprised of two statements: an else, and an if. Therefore, it needs a 'end' for the extra 'if' statement. 'Elseif' is A secure than 'else', because the lines of script after it only runs if the condition after the 'elseif' is met. Unless you want the folowing lines to be run only if the 'if' statement is false, then use 'elseif' to make sure that the lines only run if the 'elseif' condition is met.
--GOOD
score = 12
if score < 5 then --if score is below 5
print("Losing!")
elseif score > 10 then --if score is above 10
print("Winning!")
else --logically, if score is between 5 and 10 (inclusively)
print("Doing OK!")
end
--BAD
if score < 5 then
print("Losing!")
else
if score > 10 then
print("Winning!")
end
end
'Elseif' doesn't need an end, but 'else if' does, because Example 2A and Example 2B are the same.
The 'repeat' Statement
This will execute the block of code once, then keep on repeating until the 'until' condition is neither nil nor false.
a = 0
repeat
a = a + 0.1
until a == 1
print("a equals to 1!")
The 'end' Statement
This statement terminates an "if", "while", "for" or "function" statement's chunk of code.
Example for 'if':
value = true
if value then
print ("You are correct!")
end
Example for 'for':
children = Workspace:GetChildren()
for k, child in pairs(children) do
if child:IsA('Part') and not child.Locked then
child:Destroy()
end
end
Example for 'while':
while Workspace:FindFirstChild("Ball") do
Workspace.Ball:Destroy()
wait(1)
end
Example for function:
function anchor(part)
part.Anchored = true
end
anchor(Workspace.Base)
The 'local' Statement
The 'local' statement makes a variable usable in only the chunk of code it is defined in.
Example:
bin = script.Parent
function onTouched(part)
local h = part.Parent:FindFirstChild("Humanoid")
if h then
while h.Health > 10 do
h.Health = h.Health - 10
wait(1)
end
end
end
bin.Touched:connect(onTouched)
For the above code, if the variable `h` was not set as local, and two people touched the brick, only one person would be taking damage. However, since the `h` variable is local, it re-defines a new local `h` variable each time the function is called, thus allowing the function to not bug up when running twice at the same time.
If you don't use the local keyword, any assignment is considered the opposite - global. Global things can be used anywhere in a script (not just in the chunk of code it is defined in). Consider this:
a = "apple" --global `a` is "apple"
function doSomething()
local a = "banana"
print(a) --> "banana"
a = nil --sets the local variable to nil
print(a) --> "apple" (using the global variable)
end
doSomething()
The 'while' Statement
The while statement is another kind of loop. The block of code will be executed as long as the condition between 'while' and 'do' is neither nil nor false. When using true as the condition, you should always use wait() in your while statements, else ROBLOX will freeze and crash!
Example one:
while true do --this repeats forever since "true" is always neither nil nor false
wait(3)
print("Hello World!")
end
We can also instead of putting the wait after while true do, inside it, since wait never returns nil or false!
For example:
while wait(3) do
print("I waited three seconds, and this message came up")
end
Another example:
energy = 0
while energy < 10 do
wait(3)
print("Charging up...")
print(energy)
energy = energy + 1
end
Example one shows a function that will never end. Example two shows how a condition is tried each time the loop ends.
The 'for' Statement
The 'for' statement is another type of loop. There are two kinds - generic and numeric. One works with tables and iterator functions, and the other with numbers.
Numeric for is generally considered easier than generic because of it's simplicity. The format for numeric for statements is:
for a = b, c, d do
--code
end
Lua first defines a local variable `a` as `b` (`b` must be a number). It will then execute the code, and add `d` to `a`. It repeats the process until `a` is greater than or equal to `c`. You can leave out `d` and Lua assumes 1 as d.
Example one: (numeric for)
for i = 1, 10 do
print(i)
end
This executes the block of code 10 times, incrementing i by 1 each time until it is 10. Notice how the delta amount (the amount that is added)
is omitted and Lua assumes 1.
Generic for statements are a bit more difficult because they use iterator functions. Iterator functions give you the next value in some kind of list each time they are run. Lua runs the function until the iterator function does not give a value back. That's really complicated to know. In Lua, you can use the pairs() function right inside the for statement to generate an iterator function for that table.
This is a lot easier done than said. Consider this example.
Example Two:
This runs the chunk of code for every value in the `a` table.
Generic for-statements can be used to easily go through the children of an object:
Example Three:
bricks = 0
a = Workspace:GetChildren()
for k, v in pairs(a) do
if v:IsA("Part") then
bricks = bricks + 1
end
end
print("Bricks: " .. bricks)