User:Crazypotato4/Test 2
Welcome to page 2 of crazypotato4's scripting guide! Hopefully, you've learned quite a bit from page 1, but now that you've finished, you might realize that the stuff you learned there isn't even enough to make scripts that really do anything useful. Well, on this page, you'll learn everything you need in order to make cool stuff like doors that slowly turn invisible at the press of a button, or lava bricks that kill people, or even teleporters that can not only bring you from one position to another, but from one place to another!
Lesson 1: Flow Control
Flow control is when you use statements to change what parts of your scripts run at what times. It's probably used in every single one of the scripts that people make, so it's important to learn it and master it early. Flowcharts are very useful here.
If statements
The first, and most basic form of flow control is the if statement. An if statement checks if a condition is true, and if so, it runs a certain piece of code. In Lua, all values that aren't false and aren't nil are considered to be true, so the if statement basically just checks if the value is neither of those two values. The proper usage of an if statement is shown here:
if [condition] then
-- Code to do if [condition] is "true"
end
The 'end' is just to show the script that everything between 'then' and 'end' are part of the code to run if the condition is true (remember, any value besides false and nil). Here are a few examples of the if statement in use:
if true then -- true is true, so this will run the following code
print("Hello") -- this will print the word Hello into the Output
end -- show where the code inside of the if statement ends
if nil then -- nil is not true, so it won't run the following code
print("the world is ending") -- the world is probably ending if this actually printed in your output. RUN!!!
end
if 7 then -- 7 is considered true in Lua
print("yay")
end
if "false" then -- this is actually the string "false", and strings are considered true in Lua
print("lol :D") -- this will print
end
Elseif
If you want to have one thing happen if one condition is true, and another thing happen if another condition is true, instead of using two if statements, you can probably just put it all into one if/elseif statement. This doesn't apply in some cases, but in many cases, it does. You'll know what I'm talking about when you are deciding whether or not to use one yourself.
The elseif statement is used as part of an if..then..end statement. Proper usage is as follows:
if [condition1] then
--stuff to do if [condition1] is true
elseif [condition2] then
--stuff to do if [condition2] is true
end -- only one end for the entire if/elseif statement, only the if statement needs one
You can have as many elseif statements as you want in one if/elseif block. You aren't limited to just two conditions. Ex:
if false then
print("hi") -- won't print because condition is false
elseif true then
print("yay") -- will print because condition is true
elseif true then
print("wut") -- won't print because the above elseif was true
end
As you can see, only one of the sections will run, the first one which finds a true condition. This is why it is called an elseif; if the first condition is true, then run some code, else (otherwise, etc.), if this other condition is true, then run this code.
Else
Now that we have our if and our elseif, we need something that will basically be our default; the code to run when none of the conditions are true. This is the else statement. Proper usage:
if [condition] then
--stuff to do if [condition] is true
else
--stuff to do if [condition] is not true
end
The else statement can be used in conjunction with the elseif statement, like so:
if [condition1] then
--stuff to do if [condition1] is true
elseif [condition2] then
--stuff to do if [condition2] is true
else
--stuff to do if [condition1] and [condition2] are both not true
end
Some people combine an else statement with a second if statement, basically recreating the elseif statement, but requiring another end. This is not good practice, please do not do this. Just to show you what not to do, here is an example:
if false then
print("wat") -- not printed because the condition is false
else if true then -- an else statement with another if statement inside it
print("noob") -- because only noobs use this :)
end -- for the if statement that is inside the else statement, 2 lines above this
end -- for the original if statement
Scopes
A scope is created every time you open a block of code, and the scope ends once that block of code is closed. Everything in this first lesson creates a new scope when you use it. Variables can be local to a scope, meaning that they can only be accessed from that scope or any scopes inside of it (also known as nested scopes). To do this, use the 'local' keyword in front of the variable:
local Q = 4
Here is an image (uploaded by the great Anaminus) that shows how they work:
As you can see, the if statements created new scopes, and the variables local to those if statements only exist inside that scope. Once the scope ends, the variable is gone.
Loops
Loops are used when you want to repeat certain lines of code several times, sometimes until a condition is met (like in the if statement), and sometimes just for a set amount of times. In this section, you will learn the three basic loops that are used in Lua.
While
The while loop takes a condition, and as long as the condition is true, it will run the code inside. The syntax of a while loop is as follows:
while [condition] do
--stuff to do while [condition] is true
end
The condition is just like in the if statement section, only instead of just running the code once, it continues to run the code until the condition is false. An example:
a = 1
while a < 10 do -- do the following code as long as 'a' is less than 10
print(a) -- print what 'a' is
a = a + 1 -- add 1 to 'a' by defining it as what it currently is plus one
end
Your output should show the numbers 1 through 10 if you run that code.
Repeat
The repeat loop is similar to the while loop, except that it will run the code as long as a condition is not true, rather than while it is true. The repeat loop uses a conditional statement, called the 'until' statement. Proper usage of the repeat loop shown below:
repeat
--stuff
until [condition]
Unlike the while loop, the condition has to be false for the loop to run rather than true. Another difference between the repeat loop and the while loop is that the repeat loop will run the code before checking the condition, so it will always run code at least once, and the while loop checks the condition first, then runs the code, so if the condition is false, the code is never run. Examples:
while false do -- make the condition false, so the code won't run
print("hi") -- this won't print, because the condition was already found to be false
end
repeat
print("bye")
until true -- the condition is true, so the repeat loop will stop running once it hits this point. It will have already run the code inside once, though, so 'bye' will be printed to your output.
For
The for loop is different than the while and repeat loops, because it uses not a condition, but a number to figure out when it is supposed to end. The syntax of a for loop is as follows:
for [var] = [start], [finish], [increment] do
--code to run
end
The way the for loop works is, it first sets the variable [var] to the number that you put in [start], and it adds [increment] (which is also a number) to the variable every time the for loop runs until it reaches [finish], another number. If you don't have increment in your loop, then the script will just assume that it is positive 1. Note that the for loop and the while loop both need an end to finish the loop.
Examples of the for loop:
for a = 1, 5 do -- the increment isn't put here, so the script just makes it 1
print(a) -- this will print the numbers 1, 2, 3, 4, and 5 in your output
end
for potato = 50, 0, -0.5 do -- this starts at 50, and goes down to 0 by 0.5s. You have to make it negative for it to go down, the script won't do that for you.
print(potato - 2) -- just subtract two for the heck of it
end
The for loop is sometimes used to look through a table, also known as 'iterating through the table. Since table keys start at 1, and using the # length operator on a table can usually get you the amount of indexes in it, using a for loop can get each value in the table like so:
table = {"hi", 4, false, "potato", nil}
for i = 1, #table do
print(table[i]) -- since 'i' is a number, you can use it as the numeric index in the table and retrieve all the values in it.
end
Break
Break is used inside loops to simply end the loop. It stops it from running any more, it just exits the loop. Here's an illustration of how I like to think of the break command (disregarding the fact that I did a terrible job of this using MS paint):
See, isn't it beautiful? Jokes aside, this is basically what the break command does in your script, it makes the script exit the loop. To use the break command, simply type 'break' inside a loop:
while true do -- a loop that will never end, and possibly crash your game if nothing is done about it
print("hi")
if true then -- an if statement, because that's what you'll usually use when breaking the loop
break -- exit the loop, stopping it from running
end -- You must end the scope after using the break keyword, else the script will raise an error.
end
That will print 'hi' into your output once before the break command exits the loop for you. Of course, it's usually just as simple to use the condition given in while and repeat loops, but sometimes you can't, so you have to use break.
Functions
Functions let you organize your code to control how and when it is run. There are two different ways to create a function, either the keyword function followed by a set of parenthesis, or the keyword 'function', then a name for the function, then two parenthesis.
function( ) -- one way to make a function
function Something( ) -- another way to make a function
Functions require an end to mark the end of the function, just like for loops, while loops, and if statements.
function( )
end
The first thing you may be wondering is, "why do I need to have those parenthesis?" Well, the parenthesis are also known as function parameters. These are a way to give data to the function when you call the function (calling the function is how you run the code inside it). The parameters of a function are variables, but you don't set them there, they get set from outside the function. Here's an example of a parameter called 'num' being used:
function( num )
end
Not very exciting yet, is it? Well we'll start making the function cooler soon enough. Patience.
The next thing you're probably thinking from the first part of this section is, "what is the difference between saying function() and function Something()?" The difference is that when you add the name of the function, that name will be set as a variable and it will contain that function. Yes, functions are another type of data. In fact, they are a type of object, just like tables. You can also set a variable to the function the normal way:
Something = function() end
But setting it with function Name() is preferred.
In order to run your function, you use a function call. To do that, you just type the name of the function, and a set of parenthesis. These parenthesis are called arguments rather than parameters, and inside them you put the values that the parameters will be set to when the function runs.
As a quick example, let's write some code that will use a function to print a number with 7 added to it.
function plusSeven( num ) -- define function plusSeven with the argument of 'num'
print( num + 7 ) -- print num plus seven
end -- end the function
plusSeven( 4 ) -- call the function with the first parameter, num, set to 4. this will print the number 11 to your output.
If you don't give the function any arguments, then the parameter will be nil by default. If you give more arguments than there are parameters, then the extra arguments will just be ignored.
function Something( parameter ) -- create the function, make its first parameter 'parameter'.
print( parameter ) -- print the first parameter
end
Something( 7 ) -- prints 7
Something( ) -- prints nil
Something( "hi", 4 ) -- prints hi
Parameters are local to the function that they are defined in, so they can't be used anywhere outside of it.
function Add( num1, num2 ) -- a function to add two numbers
print( num1 + num2)
end
Add( 7, 1 ) -- prints 8
print( num1 ) -- nil
Scopes don't apply as you might think with functions, as they can't access variables in the scope that the function was called from unless the function was defined in the scope. The scope worries about where the function was defined, not where it was called. This can allow you to do some cool stuff with functions, for example:
function Init( num ) -- a function to create another function. the function inside this doesn't exist until this is called
function Step() -- a function that will print a number
print( num ) -- the function has access to this variable, no matter where it was called from.
num = num + 1 -- assign num to 1 higher than itself (add 1 to num)
end -- end function Step
end -- end function Init
Init( 5 ) -- call Init with a value of 5, which will allow us to use the function Step
Step() --> prints 5
Step() --> prints 6
Step() --> prints 7
This might seem useless to you know, but it can be quite useful in some situations. One place where it can be used is iterative functions, but those are a but complicated, and are used with a slightly more advanced topic than we are dealing with now.
Return
Now, we have functions that can do stuff, but what if we want the script to be able to do something with the final result of what the function did? We need a way for the function to give the value back to the rest of the script, otherwise we would have to use variables in a messy and complicated way. How we do this is with the return keyword. It allows you to pass values back to the function call. Here's basically how it works:
function Hi()
return "Hi" -- return the string Hi back to the function call
end
var = Hi() -- the value "Hi" was returned from this function call, so now var = "Hi"
print(var) -- prints Hi
The return keyword can return multiple values by separating them with commas.
function Hi()
return "Hi", "Bye"
end
var1, var2 = Hi()
print(var1) -- prints Hi
print(var2) -- prints Bye
Like break, return requires you to end the scope immediately after.
The rules of functions are not changed with return, you can use things like parameters and everything.
function Add(a, b) -- adds a and b
return a + b
end
print(Add(1, 2)) -- prints 3
When you return a function call to the function you're already in, it is called a tailcall. Ex.
function wat()
return wat()
end
This will crash your ROBLOX Studio if you try to run it, as it works similarly to an infinite loop. These are useful in some cases, however.
Lesson 2: Misc. Topics
Now, you've really come quite far in scripting, if you've read through all of this then you know basically everything you need of Lua to start scripting! But, there are a few things that all Lua users should know by this point, and I thought that I'd just stick them all here in this section.
Infinite Parameters
Since functions are fresh in your mind since they're the last thing we covered, the first thing I'll show you has to do with function parameters. I said earlier that functions will ignore arguments that don't have a matching parameter, but say you want to have that not happen, or if you want to make a function where you don't know how many parameters will be given. To do that, you use three dots/periods (...) as the function parameters.
The easiest way to use these parameters is to put them all into a table. Since the ... already contains all the values that were passed to the function, you can just put the ... in a table and you have all the arguments passed!
function PrintManyThings( ... )
local Params = { ... }
for i = 1, #Params do
print(Params[i])
end
end
PrintManyThings( "Hi", 4, "POTATOZ" )
The output would print each of those values one at a time. That function can be called with any number of arguments, and it won't matter!
Tables and Numbers
I'm not going to re-document the table and math libraries in this post, but their pages can be found here and here. The string library has a few functions that we aren't going to cover until later, so you can look through that library for stuff you might use, but I'm going to show more about some concepts used there later in this scripting guide.
The Ternary Operator
In Lua, the idiom x and y or z is often called the ternary operator. What it does is basically, if the boolean condition x is true (like in other conditions, it just needs to be not false or nil, not exactly true), then the idiom returns the value y, else it returns the value z. It's often used to avoid having to use if/else statements to change a variable.
local Condition = true
local Stuff = Condition and 1 or 2 -- if Condition then Stuff = 1 else Stuff = 2 end
While True Do
Many amateur scripters call the while loop the "while true do" loop. This is because people often use true as the condition for their while loop so that it will run forever. If you do this without using the wait function, then your game will crash. Why? Well, the while loop will attempt to run an infinite amount of times in zero seconds. That means that the computer will try to run the code inside the while loop infinite times, instantly. No computer is powerful enough to do this, so the ROBLOX app will crash. This is an example of using it without a wait:
while true do -- true is always a true condition
print("hi") -- the game will try to print 'hi' to the output infinite times instantly. That takes up too much memory and processing power and stuff, so the game crashes.
end
An easy way to stop this is by using
wait()
as the condition. This will work because, when you don't give wait any arguments, it will wait for your default amount (0 by default, change it in your settings). If the wait function is given any argument lower than one frame (about 0.033 seconds), then it defaults to waiting for one frame. The function then returns the amount that it waited (and the time that the game has been running, but we aren't concerned about that now). Since that time is a number, and numbers are considered close enough to true when dealing with conditions, the while loop will continuously run, but at least with some wait.
Indenting Your Code
When writing code, it helps to use tabs to keep your code organized. You can see me doing this on all of my code above. The way that people usually do organize tabs is, after you start a new scope, add one more tab. When you end that scope, go back one tab. Ex:
function Hi() -- start a new scope (no tabs)
local q = 4 -- (one tab)
if q == 4 then -- start a new scope (one tab)
print("hi") -- (two tabs)
end -- end a scope (one tab)
end -- end a scope (no tabs)
It's also useful to tab when you start a table, especially if your table has a lot of tables inside it (multidimensional tables). Ex.
local Tab = {
"Potato",
{
true,
1337,
{
"trololo",
"Hi",
"waffulz"
},
}
}
The Roblox API
First question that comes to mind when you see the title: What the heck is an API?
API stands for application programming interface. Now, to break it down further:
application - a program that runs on your computer, in this case, Roblox.
programming - basically, scripting.
interface - something that allows two things to interact with each other, in this case, for your scripts to interact with your game.
This section will be teaching you how to take everything that you've learned so far, and putting it to use.
How the Game is Organized
All of the games in Roblox are organized in the same basic structure. It can be illustrated kind of like a tree, so if you want to imagine that in your head while reading, that's perfectly fine.
The trunk of the tree is the game itself, also known as the DataModel (that's just the name of the object that the game actually is). This is what holds everything.
Then, there are lots of branches of the tree. These are known as services. We won't go into each service right now, but the services are just organizational objects that each have a specific purpose. The first service that you want to know is the Workspace service. Workspace is where everything that shows up in your game is. All of the bricks and models and decals (which are known as instances, along with everything else in your game) all go into Workspace. Workspace is also one of the only places that your scripts will actually run in.
A Parent-Child Relationship
In Roblox, when we talk about one object being inside another object, we say that the object that is holding the other object is the parent of that other object, and that the objects that it holds are its children.
The first object that we will be looking at is the game, or the DataModel. In all of the scripts you use in Roblox, the game already has a variable defined for it, "game" or "Game" (either works). To get a child of the object, you simply index it like you would a table, and look for the child's name. In this case, we'll look for the Workspace service, which happens to be named "Workspace". We'll also set a variable to that, just because we are cool.
var = game.Workspace
You might be thinking that this looks a lot like indexing a table right now. Well, it's almost like that, but it's different. When we work with objects, the data type that we are using is called a "userdata". We'll get to that in just a second, first we're going to look at more examples just to get used to this.
a = workspace.Model.Part
Since the Workspace service is used so much, there is a variable in every script that refers to the Workspace service in your game. Actually, there are two. Both 'Workspace' and 'workspace' are the same as saying 'game.Workspace'. While we're at it, Game also works instead of game, and game.workspace will also work to find the Workspace in your game. So what this line of code does is, inside Workspace, it finds the first thing named 'Model', then inside that model finds the first thing named 'Part'.
b = workspace["Part 1"]
Just like when using tables, if there's a name that isn't a valid identifier, you have to use brackets to get its value.
There isn't much more to talk about with this without going into topics we'll talk about later, so now, let's take a look at userdatas.
Userdatas
According to the Lua Documentation:
The type userdata is provided to allow arbitrary C data to be stored in Lua variables. This type corresponds to a block of raw memory and has no pre-defined operations in Lua, except assignment and identity test. However, by using metatables, the programmer can define operations for userdata values (see §2.8). Userdata values cannot be created or modified in Lua, only through the C API. This guarantees the integrity of data owned by the host program.
What this means is that, a userdata is basically a blank piece of data that a programmer can edit to his/her liking using metatables or by programming it in C, which only the admins can do on Roblox.
In Roblox Lua, the newproxy function, the only way to create userdatas using Lua, is probably going to be removed, possibly to save memory and possibly because of exploits related to it. We will, however, go over it in a later lesson when we are using metatables.
Another thing to note about userdatas is that they are objects, which, as we said in the Tables section of this guide, is a type of data where a variable doesn't contain the data itself, but a reference to the data.
Properties, Methods, and Events
Earlier in this section, we talked about indexing the children of instances. Well that's not the only thing that you can index. The data stored inside all instances can be put into three categories.
Properties
In Roblox, a property is data that affects an instance. The six properties that are in all objects are Name, ClassName, Parent, Archivable, RobloxLocked, and DataCost. The last three are not important to you right now, but Name, ClassName, and Parent are the basic properties that everyone should know how to use.
Name - string - Determines the name of the instance. You use this to index an object from its parent (Object.NameOfChild).
ClassName - string - Tells what exactly the instance is (a Model, a Part, a Script, etc.). This property is read-only (you can't edit it, but you can see what it is).
Parent - instance - What the instance is a child of/inside of. We talked about indexing an object to get its children just a little while ago, and this property is how you go in the opposite direction.
There are many other properties that are unique to only a few objects, each of which does a different thing. You can search for it in the search bar on the right of the page, or by going here.
Methods
Methods are functions that are members of objects, sometimes called member functions. The first argument passed has to be an instance, usually the instance that you are indexing. In order to automatically pass this first argument, you use a colon (:) to index the method. Let's use the FindFirstChild method as an example, which, when called with a colon, has one necessary additional argument (plus one other that I won't go over now), the name of the instance that you're looking for.
workspace:FindFirstChild("Potato")
Is the same thing as
workspace.FindFirstChild(workspace, "Potato")
This same principle applies to functions that are members of tables, you can index them with a colon and have the table passed as the first argument to the function call.
tab = {
Example = function(self, ...) -- when called with a colon, Self becomes Tab
print(...)
end
}
tab:Example("Hi") --> Hi
In fact, there is even a syntactic sugar (syntactic sugars are syntax shorcuts that let you do certain things with a different, sometimes better looking, syntax) to do this:
tab = {}
function tab:Example(...) -- When you put a colon instead of a dot between the table's name and the function's name, an argument is added and is called 'self'.
print(self == tab)
end
tab:Example("Potatoez!") --> true
Events
Events are a little different than plain old properties and methods. Events are, well, events. Events are when something happens. When that certain something happens, we say that the event has fired.
Events have methods as well, just like the instances that they are parts of. In each event, there are two methods that we want to be using:
- connect - This method 'connects' a function to that event, so whenever the event fires, it calls the function.
- wait - This isn't like the wait function that we looked at briefly earlier in this guide. This will completely stop your script until the event has fired.
The connect method takes one added argument, which is the function that we are connecting to the event. Let's use the Touched event, which is in all BaseParts as an example (this is assuming that there is a Part in the Workspace named 'Part'):
function Touch() -- It's helpful to name your functions something related to what they do, or what event they are connected to
print("The part was touched")
end
game.Workspace.Part.Touched:connect(Touch)
The function part is pretty self-explanatory, right? When the function gets called, it prints something. But let's look at the connection line real quick.
game - the DataModel that contains our entire game
.Workspace - we're indexing the game and finding something named 'Workspace'. That's the Workspace service, which is where we put all the bricks and stuff in our game.
.Part - here, we index the Workspace and find something named 'Part'. We're assuming that this is an actual Part for now.
.Touched - we're indexing the Part and finding its Touched event.
:connect(Touch) - this is calling the connect method of the Touched event, and the argument is the function Touch, which it will call every time the part gets touched.
So if you were to put this into a script, it would make it so whenever anything touches Part, the script will print to the output 'The part was touched'.
Some events also pass arguments to the function, for example, the Touched event passes the argument of whatever touched the part. So in the previous example, it would pass the argument of whatever touched game.Workspace.Part. Obviously, to use the argument, you need to have parameters for your function. So here's an improved version of the above script:
function Touch(obj) -- if our Part touched your game's baseplate (named 'Base'), then obj = the baseplate
print("The part was touched by" .. obj.Name) -- we're using the concatenation operator, which we learned about briefly on the last page.
end
game.Workspace.Part.Touched:connect(Touch)
So if our part touched something named 'Base', the output would say 'The part was touched by Base'.
The connect method also returns something (just like regular functions, methods can return things to the method call). It will return a connection (also known as a RBXScriptConnection). This is a pretty simple object, it only has one method, named 'disconnect'. This will do just as it says, disconnect the connection. When you call disconnect, it will make the function not get called any more when the event fires. For example:
function Touch()
print("The part got touched")
end
connection = game.Workspace.Part.Touched:connect(Touch)
wait(5) -- after 5 seconds,
connection:disconnect() -- disconnect the function.
This script will only call the Touch function if it was touched in the first 5 seconds of this script running.
Now on to the wait method. This will pause the script until the event has fired. So let's say we have this code:
game.Workspace.Part.Touched:wait()
print("hi")
The script would stop until the Part gets touched, then it would print 'hi'. Then the script would end. This is different from the connect method in two ways. First, it only works once, while the connect method will call the function it's connected to as many times as the event fires. Second, it will pause the script, while the connect method won't interrupt the script running. We'll talk about why this is later.
Just like how the connect method sometimes passes arguments to the function it connects, the wait method will return those same values that the connect method would pass as arguments. So if we were to say
local thing = game.Workspace.Part.Touched:wait()
print(thing.Name)
That would print the name of the first thing that touches Part.
The wait method isn't used by many beginner scripters because it isn't talked about in other beginner scripting guides. This is just because the connect method is more useful in more situations. It's still good to know the wait method, though, because you never know when you'll need it.