-
Notifications
You must be signed in to change notification settings - Fork 116
Lua Starfall Crash Course
Name edited this page Mar 22, 2021
·
14 revisions
--@server
-- This means code will only run on the server. shared means code will run on clients and the server. client will just be ran on the client
-----------------------------------
--Part 1: Global/Local Variables --
-----------------------------------
x = 5
-- variable 'x' now contains the number 5 and is 'global' so it can be accessed from anywhere else in the Lua program and it will stay forever or until set to 'nil'
print(x)
-- This will show the value of x in your chat
local x = 2
-- This defines a 'local' x that contains 2. After this definition, 'x' will refer to the local
print(x)
print(_G.x)
-- You can still access the global by using _G.x
-- _G is a 'table', you'll learn those in Part 6
_G.x = 10
x = 4
print(_G.x)
print(x)
-- We prefer to use 'local' instead of 'global' because they have faster accessing and their memory is managed more efficiently
-- 'global' is really only used to store stuff you want every piece of code to have access to, like libraries.
-- Even then, most scripts will access the library from 'global' once by doing "local mylibrary = mylibrary"
local math = math
print(math.sqrt(5))
-- math library usage is sped up by 'local'
-- The disadvantage to 'local' is that you are only allowed 256 of them per function and they are destroyed when their 'scope' ends (see part 2).
------------------------------
-- Part 2: Locals' Scope --
------------------------------
local x = 5
if true then
local x = 10
if true then
local x = 3
print(x) -- 3
end
print(x) -- 10
end
print(x) -- 5
-- A 'local' defined in a 'scope' will be destroyed once the scope ends. The most recent 'local' takes precedence
local x
if true then
x = 4 --this x will refer to the most recently defined local
end
print(x)
-- The only way to use a local inside and outside of the scope is to define the local before the scope.
---- List of scopes ----
do
x = 1
end
-- This is a basic scope. It does nothing but act as a scope
if true then
x = 2
end
-- This is an 'if' scope. program execution will only enter it if the condition is satisfied
(function()
x = 3
end)()
-- Functions are similar to the first scope, but can be stored as variables and executed at will.
while x == 3 do
x = 4
end
-- This is a 'while loop'. It will execute code inside it repeatedly until the condition is dissatisfied
for i=1, 1 do
x = 5
end
-- This is a 'for loop'. It will execute code inside until the specified number of iterations is done.
local myFunction = function() if x == 6 then return nil else return true end end
for k in myFunction do
x = 6
end
-- This is a 'for in loop'. It will keep calling 'func' and executing code inside until func returns 'nil'
repeat
x = 7
until x==7
-- This is a 'repeat until loop. It will execute code until the condition is satisfied
------------------------------
-- Part 3: Basic Types --
------------------------------
local String = "hello"
local Number = 108
local Function = function() print("hey") end
local Nil = nil
local Boolean = true
local Table = {}
print(type(String))
print(type(Number))
print(type(Function))
print(type(Nil))
print(type(Boolean))
print(type(Table))
-- Each Lua type has its own abilities
-- String: string stores raw data and the 'string' library contains functions to manipulate and find data within them
-- Number: numbers can be used for math of course. The 'math' library contains functions for numbers
-- Function: functions contain code and allow you to execute it
-- Nil: nil allows you to know if the variable has been defined or not; if it hasn't, it is nil.
-- Boolean: booleans are like numbers but can only be 'true' or 'false'
-- Table: tables can store anything and can be indexed with anything; they are what makes Lua so powerful. The 'table' library has some useful functions for them
------------------------------
-- Part 4: Operators --
------------------------------
print(String .. " this is a string")
-- Prints the result of combining a string with another string
print(#String)
-- Prints the number of characters in the String
print(String == "hi")
-- Prints whether the String is equal to "hi"
print(String ~= "hi")
-- Prints whether the String is not equal to "hi"
print(Number + 3 - 1)
-- Prints the result of adding 3 to Number and subtracting 1
print(Number * 2 / 3)
-- Prints the result of multiplying Number by 2 and dividing by 3
print(Number ^ 4)
-- Prints the result of exponentiating Number by 4
print(Number == 100)
-- Prints whether the number is 100
print(Number ~= 100)
-- Prints whether the number is not 100
print(Number > 100)
-- Prints whether the number is greater than 100
print(Number >= 100)
-- Prints whether the number is greater than or equal to 100
print(Boolean and String == "hi")
-- Prints whether our boolean is true and string is 'hi'
print(Boolean or not Boolean)
-- Prints whether out boolean is true or not true
-- Operators can be combined to form more complex expressions
print(Number == 100+8 or String == "hi")
-- The order of operators follows a specific order, or left to right for same operators, except '..' and '^' go right to left.
-- https://www.lua.org/pil/3.5.html
------------------------------
-- Part 5: Functions --
------------------------------
-- All Lua code is contained inside of functions. You can create and execute them at will
local Function = function() print("hey") end
-- Here we store a function that prints 'hey' into the Function variable
Function()
-- This executes the function and when the function is finished, the script returns here where it left off.
local x = 5
Function = function() print(x) end
Function()
x = 2
Function()
-- Functions can use local variables defined outside of them, but is limited to 256 locals. Globals are unlimited.
function Function()
if x == 2 then
print("x is 2")
else
print("x is not 2")
end
end
-- This is a more common way to define functions; it is the same as before, but the variable assignment just looks different.
function Function(x, y)
return x+1, x+2, #y
end
local a, b, c = Function(100, "hello")
-- Any type of data can be given to and received from functions
-- Here we give it a number and string, and get three numbers back.
-- The x, y are function 'arguments' and act as new locals
function Function()
local x = 0
return function() x = x + 1 return x end
end
-- Functions can even return functions
local func1 = Function()
local func2 = Function()
print(func1(), func1(), func2(), func1(), func2())
-- Notice how each returned function gets it's own 'x' local
function Function(func)
if func() then
print("func worked!")
end
end
Function(function() return true end)
-- You can give functions to functions too
------------------------------
-- Part 6: Tables --
------------------------------
-- Tables can store anything
Table = {"hello", function() print("hi") end, 193782, 1212}
-- Here we store 4 variables into the table, sequentially. "hello" is at index 1, "function() end" is at index 2, "193782" is at index 3, etc.
print(Table[1])
-- To access the data, we have to 'index' it. 1 is the index of "hello" so "hello" is printed.
Table[2]()
-- This calls the function at index 2
Table[3] = Table[3] + 1
-- We can assign new values into the table as well
Table = {1, 2, 3}
local Table2 = Table
Table2[2] = 5
print(Table[2]) -- 5
-- Tables are 'mutable'. This means when you assign a table to a new variable, indexing that variable will access the original's data
for i=1, #Table do
print(type(Table[i]))
end
-- Loops and tables are very commonly used together
for k, v in ipairs(Table) do
print(type(v))
end
-- Another way to loop through the table. ipairs only works on sequential 'array' tables.
-- Tables contain two ways of storing variables: this first way, as an 'array' where indeces are positive integers. The second way is the 'hashmap' where indeces can be anything.
Table = {5, 6, 7, 8}
-- This is an array; the indeces are 1, 2, 3, 4
Table = {a = 5, [1.567] = 6, [true] = 7, ["hello_world"] = 8}
-- This is a hashmap; the indeces are "a", 1.567, true, and "hello_world"
print(Table.a, Table["a"])
-- Indexing or assigning string keys to the hashmap doesn't need the " quotes unless illegal characters, like _ / - etc. are used.
for k, v in pairs(Table) do
print(k, v)
end
-- 'pairs' is used for looping over a hashmap table. 'ipairs' is used for array tables.
-- A table can be both an array and a hashmap
Table = {[1] = 1, [2] = 2, [3] = 3, [4] = 4, a = 1, b = 2, c = 3, d = 4}
for k, v in ipairs(Table) do
print(k, v)
end
for k, v in pairs(Table) do
print(k, v)
end
-- Notice that 'pairs' will read the 'array' part of the table too, but 'ipairs' will only read the 'array' part.
-- Also the order that 'pairs' reads is random
function table.count(tbl)
local count = 0
for k, v in pairs(tbl) do
count = count + 1
end
return count
end
print(table.count(Table))
-- We can store functions inside tables like this for 'libraries'. Here we store a function in the 'table' library that returns the number of objects in the given table.
function math.average(tbl)
local avg = 0
for _, v in ipairs(tbl) do
avg = avg + 1
end
return avg / #tbl
end
print(math.average({1, 5, 8, 3, 2}))
-- The # operator allows us to get the number of elements in 'array' tables. However if there's 'nil' anywhere in the sequence then it won't work.
Table = {1, 2, 3, 4, nil, 5, 6, 7}
print(#Table)
-- The 'nil' will screw up the # operator. It's best to avoid nil in an 'array'.
Table = {1, 2, 3, 4, 5, 6, 7}
Table[#Table + 1] = 8
Table[#Table + 1] = 9
-- It's easy to add stuff to the end of an 'array'. Adding or removing stuff inside them is best done using the table.insert() or table.remove() functions
local fibbinaci = {1, 1}
for i=1, 10 do
fibbinaci[i+2] = fibbinaci[i] + fibbinaci[i+1]
end
print(table.concat(fibbinaci, " "))
-- Generates the fibbinaci sequence and converts it to a string and prints it.
-- Sometimes a table will have accessible functions and also contain data
MyAngle = {pitch = 50, yaw = 10, roll = 0}
function MyAngle.Add(ang1, ang2)
return {pitch = ang1.pitch + ang2.pitch, yaw = ang1.yaw + ang2.yaw, roll = ang1.roll + ang2.roll}
end
Angle2 = MyAngle.Add(MyAngle, MyAngle)
-- Another way to write it is:
function MyAngle:Add(ang2)
return {pitch = self.pitch + ang2.pitch, yaw = self.yaw + ang2.yaw, roll = self.roll + ang2.roll}
end
Angle2 = MyAngle:Add(Angle2)
-- This shortcut is commonly used for object oriented programming
-- Table.Function(self, ...) is replaced by Table:Function(...)
-- 'self' is the table that the function was called with.
Ball = class("Ball")
function Ball:initialize()
self.x = 0
self.y = 0
self.dx = 0
self.dy = 0
end
function Ball:think()
self.x = self.x + self.dx * timer.frametime()
self.y = self.y + self.dy * timer.frametime()
self.dy = self.dy + 9.8 * timer.frametime()
end
local Balls = {Ball:new(), Ball:new(), Ball:new(), Ball:new()}
for _, v in ipairs(Balls) do
v:think()
end
-- This simple example shows creating 4 ball objects and running their 'think' functions. Each ball table contains its own data and 'self' refers to the ball that the function was called with.
------------------------------
-- Part 7: Starfall --
------------------------------
-- The Starfall script is only ran once when the chip initializes. 'Hooks' are used to run code when events happen.
hook.add("think","mythinkhook",function() print("hello") end)
-- Here we give a function that prints "hello" to the "think" hook which will call the function each game tick. We named the hook "mythinkhook" and that can be used later with hook.remove() to remove the hook.
wire.adjustInputs({"Button","Ent"},{"Number","Entity"})
-- Here we give a table of inputs and a table of their types to assign the chip's wire inputs
hook.add("input","",function(key,value)
if key == "Button" and value == 1 then
print("The button was pressed!")
print("Ent is " .. tostring(wire.ports.Ent))
end
end)
local myhologram = holograms.create(chip():getPos(), Angle(), "models/error.mdl")
myhologram:remove()