Hello!
I’ve written this guide/tutorial to help people who are new to scripting on Roblox learn some basic concepts of scripting, and hopefully understand it better. This is definitely missing a lot of important information, but I will be updating it more in the future!
If you’re brand new you should read The Basics
below, but if you know about variables, functions, and data types you should skip to Concepts
, where I explain some of the Roblox-specific ideas that’ll allow you to read the information on the devhub (https://developer.roblox.com)
The Basics
Data types
Strings
Strings hold text! They are surrounded by double quotes, "
, or single quotes, '
. They can also be surrounded with [[
and ]]
to make them span across multiple lines, which is usually called a “multi-line” string.
Tables
Tables hold data. You may have heard of arrays which are lists, or dictionaries which “map” a specific thing to another. Dictionaries are sometimes referred to as objects, like in JavaScript. Tables work as an array or a dictionary, and can even work as both at once.
{"My array", "is cool"} -- Like a dictionary, but the indexes are numbers in order, and there are no gaps.
{["My object"] = "is cool"} -- Can have indexes with any value, even other dictionaries. It can be an array too.
Booleans
Booleans are either true or false, yes or no. They aren’t much, but they offer a lot of use in programming. When you compare values in programming languages you’ll get a boolean.
1 < 3 -- One is less than three, so true
4 == 2 -- Four doesn't equal two, so false
6 > 7 -- 6 is less than 7, not greater than, so false again
Numbers
Numbers, 1, 2, 3, and anything else. In a lot of other programming languages numbers can either be an integer (a whole number), or a float/double (which store numbers with decimals, kind of like scientific notation).
Lua numbers can contain decimals. You can use fractions too, by dividing: 1/5 = 0.2
Variables and functions
Variables are simply a way to store a single thing in them. They can hold anything, and are one of the most important features in all programming languages. In lua they can be local, meaning they can be used where they are created, or global meaning they can be used anywhere.
variable = "My string" -- A global
local localVariable = "My other string" -- A local
do -- I don't do anything special, but I have my own set of locals, which is called a scope.
print(abc) -- I can't see the variable yet, so I access a global, but since there is no global named that I will print "nil" which means no value. It's sort of like "null" in other programming languages.
local abc = 123 -- I only exist inside of my scope, under this do statement, and I can be used by future code
-- Everything past here can see the abc local now:
print(abc) -- prints 123
end
print(abc) -- I can't see the abc local, since its in a different scope, so I use the global abc, which is nil still.
Functions can run the same code multiple times. Functions can be local too, and are just a type of value.
local function myFunction(a, b, c) -- These are like local variables. They're called arguments, and they can be given to the function when you "call" it
return a, b, c
end
print(myFunction(1, 2, 3)) -- This calls the function and gives it 1, 2, and 3 as its arguments. This calls `print(1, 2, 3)` because myFunction returns all three numbers.
local myFunction2(a, b, ...) -- ... Is like a variable but can only be created inside of a function's arguments. It represents multiple values at once
print(a, b) -- This will print the first two arguments
warn(...) -- But this will warn any other arguments
end
myFunction2(1, "b", 2, "d", 3, "f")
Statements
Statements make up code.
There are different types of statements.
For example, the if statement, which executes code, if a condition is true. If statements use booleans!
if true then
print("It ran!")
end
if false then
print("You won't see me because the condition is false!")
end
Remember nil? Nil acts like false in an if statement. And all other values act like true.
if nil then
print("I won't execute!")
end
if not nil then
print("Not nil is true: "..tostring(not nil))
end
if 2 then
print("Number!")
end
if {} then
print("Table!")
end
If statements also have else and elseif clauses.
If one thing happens do this, otherwise, if this (elseif) then do this, otherwise (else) do this
if thing1 then
-- thing1
elseif thing2 then
-- not thing1, but thing2
else
-- not thing1 or thing2
end
There are many statements that do different things, like the do statement from earlier, but if statements are one of the most important statements in programming because they make up all of the logic of your code.
Loops
Loops are super important too. They let you run code for all of the items in an array or dictionary or repeat things a certain number of times. They can also repeat forever, or until a condition is met, allowing you to do something repetitively without writing a function call for every one of them.
Prepare for a lot of information!
There are three main types of loops.
While and repeat loops
while myCondition do -- These loops repeat while a condition is truthy. That works like an if statement does.
-- Stuff
end
repeat -- These loops are like while loops but they repeat *until* a condition becomes truthy. They are like the opposite of while loops, but, they also run their code before they check their condition, allowing you to always run their code at least once.
-- Stuff
until myCondition
-- Repeat loops can also be represented as a while loop:
-- Stuff (since the condition is checked after code runs in a repeat until loop)
while not myCondition do -- This will keep looping *until* myCondition becomes true.
-- Stuff
end
For loops
-- There are two main types of for loops
-- There are these loops, which "count". You can use them to repeat something any number of times.
for i=1, 10 do -- i is a local. It represents the current "index." It can be named anything you want!
print(i) -- The index gets printed. You would see the numbers from 1 to 10 in your output
end
for i=1, 10, 2 do -- For loops like these also have a third option. This is the "step" option. It represents how much to add to i every time the loop repeats (iterates). It can even be negative.
print(i) -- You should see the odd numbers from 1 to 10.
i = i + 100 -- You can also add to i and it won't effect the next iteration of the loop.
warn("I added 100 to i! "..i)
end
-- The second main type of for loop are these loops. These are also known as "foreach" loops because they loop "for each" thing in an array or dictionary
local tbl = {
["abc"] = 123,
[1] = "abc",
"def" -- This actually has index 2. It's like writing [2] = "def"
[3] = "I am number 3!", -- That means that you don't need to write [3] here
"I am number 4!",
"I am number 5!",
nil -- This is nil. Watch out for this later!
"I am number 6!",
[{My="table"}] = "I have a non-string index!",
[{My="table"}] = "I have a non-string index too! (Notice how I didn't overwrite the previous index) \
All complex data types (non-strings, non-numbers, non-booleans, non-nil, etc. \
Tables, Instances, Vector3s, and all others are complex) are always unique even if their content is the same." -- This string also spans multiple lines. Using \ before each new line will make sure it stays there, similar to a long string using [[ and ]]. You can also write \n and it will be a new line in your string, just like if you press enter.
}
for index, value in pairs(tbl) do -- This loop will loop through table giving you each index and the corresponding value. This condition is always true: tbl[index] == value.
print(index, "=", value) -- Using commas in print, warn, or error will add a space between each item. I prefer to use commas sometimes because it types faster and is sometimes easier to read.
-- You should see every index and its value!
end
-- But there are also these loops:
for _, value in ipairs(tbl) do -- If you change the _ to any variable name the value of that variable will be the numeric index. _ has some functionality in loops and function parameters.
-- It represents "no variable." Setting _ to something will truly create a variable with the "_" name but when used in loops and function parameters it doesn't create a variable.
-- That means that there's no variable to clean up later which can ever so slightly improve performance and reduce memory usage but it's not something to worry about. This is simply considered a "good practice" even though it doesn't offer much benefit.
print(value) -- This only prints "array-like" values. "array-like" values have an integer index from 1 to infinity. If you have an integer index set to nil *anywhere* in your table it will stop iterating.
-- You should see all of the values up to index 5 because there's a gap at index 6 which is nil!
end
-- And finally, function based for loops and next loops:
for index, value in next, tbl do -- The "tbl" value is passed to "next" (which is a function) as its first argument. Then the arguments that next returned previously are passed after it.
end
-- ipairs and pairs loops actually both return a function, just like above, and this is how those loops work
local function iteratorFunction(my123Value, lastKey, lastValue, ...) -- This is exactly like the function pairs returns. Pairs isn't represented in lua though so it's faster. It's called by the for loop when it runs, and it gives us all of the values returned previously and any extra values
print(my123Value) -- Will always print 123 since we pass it in our loop
return next(tbl, lastKey) -- This returns the next index and value after lastKey
end
for index, value in iteratorFunction, 123 do -- This uses the iterator function we created to get an index and a value. It passes 123 as the first argument and then index, value.
print(index, "=", value)
end
Concepts
These are the basics of Roblox. These are what you should know about to use the documentation on https://developer.roblox.com
Properties
These are like variables but they exist on an Instance. For example, parts have the Anchored property which can be true
or false
.
You can think of an Instance a lot like a table.
Methods
These are actually just like properties, but they are functions instead. They offer you extra functionality that properties can’t.
For example:
local Destroy = part.Destroy -- This is a function!
Destroy() -- But why can't we call it?
-- It uses a colon (:)
-- But what does : do?
Destroy(part) -- : just gives the function an extra argument, so when you call part:Destroy() you actually call part.Destroy(part)
local tbl = {}
function tbl:func()
print(self) -- Same as below
end
function tbl.func2(self)
print(self) -- Same as above
end
print(tbl) -- This will print out an id for a table
tbl:func() -- This will pass tbl as the first argument
tbl:func2() -- And so will this
tbl.func(tbl) -- And here's what it looks like without :
-- All of them print the same table id
Events
Events are similar to instances.
They have two functions, Connect and Wait.
Connect will call a function when the event is fired.
For example Instances have a ChildAdded event which is fired whenever an instance is added to it aka “parented” to it.
:Wait will wait until the next time the event is fired.
local myEvent = Instance.new("BindableEvent")
myEvent.Event:Connect(print) -- Will call print when we fire it! Event is an Event on the Instance BindableEvent. It's very similar to a property.
myEvent:Fire("abc")
Getting instances
Instances have FindFirstChild, WaitForChild, and GetChildren functions. GetChildren returns an array of instances which are the “children” of the target instance. FindFirstChild looks for an Instance with a given name and returns it. If it doesn’t exist it returns nil! WaitForChild is similar, but it waits for the instance to exist instead.
You should read the documentation pages for them!
The Instance class.
WaitForChild
FindFirstChild
GetChildren
The dos and donts
How should you find information?
Google! Googling your problems is a great place to find information. You can find everything you need on Google including devforum posts and documentation. If you’re looking for something specific though you should search for documentation directly or look on the devforum!
Neatness is important
When writing Roblox scripts I would recommend keeping your code neat. If your code is readable it means you can look back at it in the future! It’s important for you and others to be able to read your code so they can understand what it does and maybe give some tips on what you could do differently! It also gives you opportunity to reflect on your work and see how far you’ve gone.
That means name your variables clearly and indent your code!
Capitalization can give you context!
This isn’t super important but you should keep it in mind! Make sure your capitalization style is consistent. Often times (but not always) you want variables to start with a lower case letter unless it is a class, Instance, Service, or important variable. That lets people know ahead of time what a variable might be used for. It’s by no means the end of the world if your capitalization doesn’t follow that rule as long as it’s understandable and consistent!
Services in Roblox
Usually when using Roblox services people will recommend that you keep services in variables and keep them with the same name. This is generally a good idea because it lets people reading your code know what services you use before hand and it makes editing and reading code code much easier!
Example:
local ServerScriptService = game:GetService("ServerScriptService")
This format allows you to quickly double click on service names and see where they are used. It also lets you easily replace them if you make a mistake. It also helps you keep your code more organized and readable.
It’s okay to copy code - Sometimes!
Copying code from people is great! Trying to understand other people’s code is how most developers learn. It allows you to pick up on new tricks and better formats. Not everyone is perfect so it’s great to learn from people who have learned something you haven’t learned yet. But always make sure you are not using code without permission! Free models are a great place to find code, but be careful when using them in your game because a lot of them contain malicious scripts. And most importantly of all, make sure you never claim someone else’s code as your own!