Skip to content

Lua Coding Docs: Basics of Coding

Meme1079 edited this page Dec 25, 2024 · 15 revisions

Introduction

Lua is a lightweight, high-level, dynamically typed, multi-paradigm scripting language, created in 1993, Brazil It was designed to improve its speed, portability, extensibility, and ease of use in development. Which is why it is used in Psych Engine; this allows you to execute Lua code without compiling the game over and over again, unlike doing source code in Haxe.

Scripting Adjustment

Coding in Psych Engine has some "minor adjustment" compared when coding in vanilla Lua. This is due to HaxeFlixel, the main engine used by Psych Engine. Another reason is due to LuaJIT, a tracing just-in-time compiler for Lua. Anyways uuuuhhhhh here's a list of minor adjustment that you should 100% totally know about:

  1. Code should be used inside of Event Callbacks, a special event handler functions for specific game events that occured. For example: onCreate() initiated at the start of the game; onUpdate() updated in each frame; onEvent() used for creating events. Some variables or functions would not work properly if declared outside. But some variables and function, in PsychLua or not can work outside tho. For further information just click here.

Tip

In update 0.7.1h of Psych Engine you can now put code outside of any Callback Templates, which is the best feature to be ever be implemeted in years, but this will only execute once tho.

  1. Printing is slightly altered, instead of using the print() function—it's replaced by the debugPrint() function. The arguments passed on the debugPrint() function will appear at the top-left of the screen. And will fade out in a couple of second.

  2. Psych Engine uses LuaJIT for it's Lua programming language, due to this. LuaJit uses version 5.1 of Lua which is outdated and has some missing features from future versions. But it has extensions you might probably or never use like bitwise operations, FFI library, etc.

Source-Code Editors

You don't know they're basically a text editor program designed specifically for editing source code of computer programs. They usually add such as syntax highlighting, indentation, autocomplete and brace matching. To make your programming experience more easier to code, the most popular source-code editors are Visual Studio Code, Notepad++, Vim, Sublime Text, etc. You can use any source-code editors that you're comfortable to use.

If you install Visual Studio Code there are extensions which makes your coding experience even more better. Like supporting a new programming language, adding custom snippets, etc.


Comments

Comments are used to explain the context of code and what its purpose is, or to disable the execution of code. This won't affect anything inside the Lua program because it will be completely ignored.

To define a comment, they start with double hyphen characters -- for singular comments. You can place them at the start or end of any line of code, and Lua will ignored them as usually. For multi-line comments they also start with double hyphen characters --, followed by both a opening and closing square brackets [[]] with the code in-between them.

Example:

-- Creating a sprite
function onCreate() -- Triggered at the start of the Lua script
     makeLuaSprite('tag', 'imagePath', 0, 0) -- initializes the lua sprite
     addLuaSprite('tag', true)               -- Adds the lua sprite
end

--[[
function onCreatePost()
end ]]

Tip

You can also nest comments, this is only for multi-line comments tho. To do this, between the two opening and closing square brackets each must be supplying a specified number of equal characters =. This is very useful in cases where commenting out blocks of code which themselves contain more comments.

Example:

--[=[
function onCreate()
     --[[
     makeLuaText('textStuff', 'Hi', 0, 100, 100)
     setTextSize('textStuff', 20)
     setObjectCamera('textStuff', 'camHUD')
     addLuaText('textStuff')
     ]]
end

function onUpdate(elapsed)
     -- code here or something, idk
end
]=]

Variables

Variables are abstract manipulable containers for storing data values; they can be used throughout the Lua program. They're paired with an associated name, which contains the data value of the variable to be used. The data from the variable can be updated when you assign a new value to it.

Declaring & Assigning

To declare a variables you should assign the scope, identifier, and data value. The scope determins the scope level for the variable to have. It could be a global scope which is the default for all variables, or a local scope which is define with the local keyword. This is will have a limited scope to the block where they are declared. The identifier which is the name of the variable, to be referenced or used later.

Now you can assign the variable by using the assignment = operator to specify the data value to hold. If the assigning isn't present, the variable will just have a nil value as a replacement. But you could later initialize the variable later on another line of code somewhere. This only works for local variables not for global ones.

Important

I highly recommend to use local variables instead of global variables. It helps avoid cluttering the global environment with unnecessary identifiers, better performance, and are generally faster than global variables. Why there faster because local variables are stored in a memory stack while global variables are stored in a global environment.

Examples:

local object_cost1 = 20
local object_cost2 = 12
local object_price = object_cost1 + object_cost2 -- adds two object values

function onCreate()
     debugPrint(object_price) --> 22
end
local object_cost1 -- declaring a variable without any assigning
local object_cost2
function onCreate()
     object_cost1 = 34 -- assigning a local variable
     object_cost2 = 44

     debugPrint(object_cost1) --> 34
     debugPrint(object_cost2) --> 44
end

You can also re-assign variable's data value to an existing variable. If you want to change the current data value, it's just the same as assigning but with a different data value to hold.

Example:

local object_cost1 = 100 -- initial value
function onCreate()
     object_cost1 = 30   -- re-assign a new value
     debugPrint(object_cost1) --> 100
end

You can also declare multiple variables in one line if you want to reduce the lines of code for some reason. To do this, each variable's identifier and data values should be separated by a comma. Each comma , character of them should be equal.

Examples:

local pi, euler     = 3.14, 2.71     -- multiple variable declaration
function onCreate()
     debugPrint(pi)    --> 3.14
     debugPrint(euler) --> 2.71
end
local lua, haxe, js = 'easy', 'hard' -- missing variable assigning
function onCreate()
     debugPrint(lua)  --> easy
     debugPrint(haxe) --> hard
     debugPrint(js)   --> nil
end

Naming Conventions

Naming conventions are a set of special rules when you're naming an identifier, here are following rules to abide to:

  • Identifiers can have a combinations of characters e.g. digit, alphabetical, or underscore characters.
  • Identifiers cannot have digit characters at the start of the name.
  • Identifiers cannot have special characters e.g. $, ,, =, etc.
  • Identifiers cannot be named after Lua keywords.
  • Identifiers are case-sensitive so variable a and A are completely different to each-other.
  • Identifiers should have descriptive names like (health, misses, alpha) to make the code more understandable.

Example:

varname   = 'Hi'   -- a variable (lower case)
varName   = 'Hi'   -- a variable with a capitalize letter (camel case)
var_name  = 'Hi'   -- a variable with an underscore '_' character (snake case)
_var_name = 'Hi'   -- a variable with an underscore '_' character at the start
VARNAME   = 'Hi'   -- a variable that is all capitalize letters (upper case)
varname2  = 'Hi'   -- a variable with a number
_______   = 'Hi'   -- a variable with all underscores (this is real)

1varName = 'Error' -- a variable with a number at the start
var-name = 'Error' -- a variable with a minus '-' character (kebab case)
var name = 'Error' -- a variable with a space ' ' character
var$name = 'Error' -- a variable with a special '$' character

Data Types

Strings

Strings are a sequence of characters containing any characters; they could be either alphabetical, digital, punctuation, etc. Their main purpose is to store human-readable text, like words and sentences. They're commonly surrounded by either single-quotes '', double-quotes "", or even double-brackets [[]] for multi-line strings.

Example:

local textString1 = 'Hello' -- a single quote
local textString2 = "World" -- a double quote, this is optional to use
function onCreate()
     debugPrint(textString1) --> Hello
     debugPrint(textString2) --> World
end

Escape Characters

Escape characters are a special characters used within a string, they are an alternate interpretation of the characters in the following character sequence, it basically allows you to insert illegal characters inside a string. For instance a single-quote character ' that is surrounded by single-quote string, which will cause an error on the Lua program. They are define with the backslash character \ followed by the specified character to use after that; they're listed below.

Example:

function onCreate()
     debugPrint('Don\'t press \'Alt + F4\'') --> Don't press 'Alt + F4'
     debugPrint("dead \"(in a cool way)\"")  --> dead \(in a cool way)"
     debugPrint('C:\\Windows\\System32')     --> C:\Windows\System32
end
  • ' - Single-quote character
  • " - Double-quote character
  • \ - Backslash character
  • \n - New line character
  • \r - Carraige return character
  • \t - Horizontal tab character
  • \v - Vertical tab character

Numbers

Numbers are arithmetic values that represent the quantity or amount of something, it can have a positive or a negative value. Numbers can be expressed as integers (Int) which uses whole numbers, or floating-point (Float) which uses a number with decimal-point.

Example:

local int   = 47  -- integer number
local float = 2.2 -- floating-point number
function onCreate()
     debugPrint(int)   --> 47
     debugPrint(float) --> 2.2
end

Notations

Notations are used used to represent numbers in an alternative way. There is only 2 notations to alternative represent numbers.

Notations Descriptions Example
Scientific notation Scientific notation allows you to represent extremely large or small
numbers with the e notation.
34e+4 or 34e4
43e-3
Hexadecimal Hexadecimal, a type of numbering system base on 16. Each starts
with 0x followed by the preceding hexadecimal number. Obviously
used for hex coloring to objects.
0xff0000
0xbe20ab

Booleans

Booleans, often shortened to "Bools", are data types that can have two possible values: true or false. This is commonly used for conditional statements, which allow for different actions by modifying control flow based on whether the condition is true or false.

Nil

Nil represents the nothingness or non-existence of a value. This can be used to destroy a variable or table element if it is not used anymore. Or use conditional statements to check if the value is a nil or not.

Tables

Tables are data structuring mechanism and the only one in Lua, it consist a collection of values that it stores like strings, numbers, booleans, and even themselves except nil values. These are commonly used for storing values, making modules, metatables, and classes which are useful in some cases. They are constructed with curly braces characters {} and can represent as an Array or Dictionary.

If you try to attempt to call a table it will return the table's memory address; Example: table: 0x55557885d670. But in Psych Engine it returns the table elements with brackets surrounding it. If you want to read a specific element from a table, use the indexing access operation [ind] for that.

Important

Lua uses based-1 indexing for tables, unlike some programming languages. So basically instead of using [0] you use this [1]. If you asky why they did this? Becuase the Lua libraries prefer to use indices which start at 1.

Example:

function onCreate()
     debugPrint({}) --> []
end

Arrays

Arrays are an ordered list of elements and the most common type of table to define. Each elements are separated by a comma , character with a pair of curly-braces {} characters surrounding it.

To read the table's array element, add a indexing access operation which is a pair of bracket [] characters. With the given index number inside, if the index isn't present or just invalid it returns a nil value as a result of it.

Examples:

local tableGroup1 = {'string', true, nil} -- a table with string, boolean, and nil values
local tableGroup2 = {{45, 13}, {34, 76}}  -- a table with nested tables
function onCreate()
     debugPrint(tableGroup1)       --> ['string', true, null]
     debugPrint(tableGroup1[1])    --> string
     debugPrint(tableGroup2[1][2]) --> 13
end
local sillyNumbers = {29, 63, 12}
function onCreate()
     sillyNumbers[4] = 83 -- inserting
     sillyNumbers[1] = 30 -- re-assinging
     debugPrint(sillyNumbers) --> [30, 63, 12, 83]
end

Dictionary

Dictionaries use key-value pairs for storing elements instead of the index-value pairs that a table array uses. It basically uses names or keys to reference the elements inside a table dictionary. The keys from the dictionary could be either surrounded by a pair of brackets [] characters with the name to be given; Example: ['name']. If the name has a special character inside of it or not.

To read the table's dictionary element, add a dot . character with the given name of the key. Or add a pair of brackets [] characters with the given name. Really just depends what your comfortable to use when coding; Example: table.name or table.['name'].

Example:

local stupidData = {FM = 46, PCM = 12, DA = 25}
function onCreate()
     debugPrint('FM: ' ..stupidData.FM..', PCM: '..stupidData.PCM..', DA: ' ..stupidData.DA)
     --> FM: 46, PCM: 12, DA: 25
end
local stupidData = {FM = 46, PCM = 12, DA = 25}
function onCreate()
     stupidData.FM  = 12 -- inserting
     stupidData.LVL = 4  -- re-assigning
     debugPrint(stupidData) --> ["FM" => 46, "PCM" => 12, "DA" => 25, "LVL" => 4]
end

Operators

Operators are unique symbols that are used to carry out operations on operands. For the conditional statements to use to determine if the value is true or false before executing the code block. They can be represented as Arithmetic, Relational, Logical, and Miscellaneous operators.

Arithmetic

Arithmetic operators are mathematical operators used to perform calculations for numeric values.

Operators Name Example Returns
+ Addition 5 + 5 10
- Subtraction 8 - 3 5
* Multiplication 5 * 3 15
/ Division 9 / 2 4.5
% Modulus 8 % 4 0
^ Exponentiation 2^4 16
- Unary Negation -8 -8

Relational

Relational operators are used to compare multiple operands inside a condition in order for the code block to execute.

Operators Description Example Returns
== Checks if the condition is equal to the right. a == b false
~= Checks if the condition is not equal to the right. a ~= b true
> Checks if the condition is greater than the right. 4 > 5 false
< Checks if the condition is lesser than the right. 4 < 5 true
>= Checks if the condition is greater or equal to the right. 7 >= 7 true
<= Checks if the condition is lesser or equal to the right. 2 <= 5 true

Logical

Logical operators are used to combine multiple conditions and to specify on what conditions needs to be true.

Operators Description Example Returns
and Returns true if both statements are true;
Combines multiple conditions together.
a == false and b == true false
or Returns true if one of the statements are true;
Combines multiple conditions together.
a == false or b == true true
not Reverses the condition; If the condition is false
it will return true and vice versa.
not false true

Miscellaneous

Miscellaneous operators only features two operators the Length and Concatenate operators.

Operators Description Example Returns
# Length operator, Checks the maximum length size of a string or table. #'quad' 4
.. Concatenate operator, Merges multiple string or numbers together. 'snow'..'ball' snowball

Control Statements

Control Statements allow you to control the execution of other statements. Which analyzes the statement's condition and decides whether to execute the code if it's true or not.

Conditions Statements

These are a type of control structure that specifies whether or not to execute the block code. They are the most common control structures to use. There are only 3 conditional statements: if, else, and elseif statements.

If Statement

The If statement checks the condition if it's true or not. They are define with the if keyword followed by the specified condition to execute the statement with the then keyword.

Example:

local BFScore  = 354
local DADScore = 100
function onCreate()
     if BFScore > DADScore then
          debugPrint('Win!') --> Win!
     end
end

Elseif Statement

The Elseif statement checks if the other conditions failed and allows multiple conditions to be evaluated in a sequence. They are define with the elseif keyword with the specified condition to execute, followed by the then keyword.

Example:

local BFScore  = 245
local DADScore = 473
function onCreate()
     if BFScore > DADScore then
          debugPrint('Win!')
     else
          debugPrint('Lose!') --> Lose!
     end
end

Else Statement

The Else statement checks if all of the other conditions failed, if all them failed this will execute. They are defined with the else keyword and it should be declared at the bottom of singular or multiple conditions of the if or elseif statements.

Example:

local BFScore  = 250
local DADScore = 250
function onCreate()
     if BFScore < DADScore then
          debugPrint('Win!')
     elseif BFScore == DADScore then
          debugPrint('Draw!') --> Draw!
     else
          debugPrint('Lose!')
     end
end

Iterative Statements

Iterative statements allows statements to execute zero or more times, until the condition is met or it breaks the loop. They are commonly used for repeating code or iterating a table. There are only 3 iterative statements: for, while, and repeat-until loop.

For Loop

For loop statement allows you to loop a specific number of times. This loop is commonly used for setPropertyFromGroup() and getPropertyFromGroup() functions for note modification, modcharts, or something. And used for reading a table values or performing on numeric values. There are 2 types of for loops: Generic loop and Numeric Loop.

Numeric

Numeric Loop uses numeric values to increment or decrement a value. This loop is usually the most common loop to use for setPropertyFromGroup() and getPropertyFromGroup() functions. They are defined with the for keyword followed by 3 expressions: initializer, maximum, and iteration. With the do keyword last.

  • initializer - The initial variable for the numeric loop to use.
  • maximum - The maximum number for the numeric loop to stop at.
  • iteration - The iterator for the numeric loop to use you can either increment or decrement the value. This expression doesn't need to be initialized it will default, to add 1 after each loop.

Example:

function onCreate()
     for index = 0, 5 do     -- Incrementing loop
          debugPrint(index)  --> 0, 1, 2, 3, 4, 5
     end
     for index = 5, 0, -1 do -- Decrementing loop
          debugPrint(index)  --> 5, 4, 3, 2, 1, 0
     end
end

Generic

Generic Loop are another type of loop that allows you to traverse all values from a table; return from a iterator function from the in keyword. This is just an alternative loop for iterating every table elements. The defining of this loop is the same as the numeric loop, but the there are only 2 expressions: initializer and iteration.

  • initializer - The initial variable for the generic loop to use. The amount of variables depends on the iterator function that you're using, pairs(), ipairs(), and next() function only uses 1 or 2 variables. But the string.gmatch() functions depends on the captures from the string.
  • iteration - The iterator for the generic loop to use; iterators to use here are already listed above of this description. You can also use custom iterators function, if you want to, but we're not gonna talk about it. (Don't even dare)

Example:

local characters = {bf = 'boyfriend', dad = 'dad', gf = 'girlfriend'}
function onCreate()
     for k,v in pairs(characters) do
          debugPrint({k,v}) --> ["bf" => 'boyfriend'], ["dad" => 'dad'], ["gf" => 'girlfriend']
     end
end

While Loop

While loop statement will loop infinitely until the condition returns false. This is rarely used but if it is, it's only used if you're iterating based on a condition rather than number of times, the use this loop. It is declared with the while keyword followed by the condition to loop over until it returns false, with the do keyword last.

Caution

Please make sure to check the condition of the while loop. Because it might loop infinitely and crash or softlock your game! I'd suggest you testing it here before implementing into your Lua script.

Example:

local counter   = 5
local factorial = 1
function onCreate()
     while counter > 0 do
          factorial = factorial * counter
          counter   = counter - 1
     end
     debugPrint(factorial) --> 120
end

Repeat-until Loop

Repeat until statement works similarly as the while loop, but has a major differences. The block of code has a guaranteed to be executed at least once, before checking if the condition is true, it will repeat the loop until its condition is met. It is declared with the repeat keyword followed by the body of code, with the until keyword next to the condition to loop over.

Caution

Please make sure to check the condition of the while loop. Because it might loop infinitely and crash or softlock your game! I'd suggest you testing it here before implementing into your Lua script.

Example:

function onCreate()
     repeat -- me getting paid
          money = money + 1
     until money >= 10
     debugPrint(money)
end

Jump Statements

Jump statements allows the manipulate the flow of the program, if the condition is met. They are used to manage the control flow of iterative statements and functions. There are only 2 jump statements: return and break statements.

Return Statement

Return statement causes the function to terminate its execution and returns with or without the value. If the return statement didn't provide any values to return, it actually returns nothing, no nil values, it's just nothing. They are define with the return keyword obviously with the optionally provided value.

Example:

function stupid()
     return 'bf'
end

function onCreate()
     debugPrint(stupid()) --> bf
end

They can also return multiple values each must be separated by comma characters ,; Example: return 3, 4, 6. If you want to get the values convert it into a table, it will only get the first value if you didn't do it. If you don't like it using this method, you could use variables by using multiple assigning of variables depending of the returning values.

Examples:

function numbers()
     return 3.14, 420
end

local numbers = {numbers()} -- converts it into a table
function onCreate()
     debugPrint(numbers) --> 3.14, 420
end
function numbers()
     return 3.14, 420
end

function onCreate()
     pi, drugs      = numbers()     -- pi = 3.14, drugs = 420
     pi             = numbers()     -- pi = 3.14, drugs = nil
     pi, drugs, idk = numbers()     -- pi = 3.14, drugs = 420  (idk is discarded)
     pi, drugs, idk = numbers(), 47 -- pi = 3.14, drugs = 420, idk = 47
end

Break Statement

Break statement forcefully stops any iterative statements from looping. This mainly used to forcefully break the loop on a specific condition that is set on. This is define with the break keyword obviously.

Example:

function onCreate()
     for index = 0, 30 do
          if index > 10 then
               break
          end
          debugPrint(index)
     end
end

Functions

Functions (also called subroutine or procedure) are sequence of code that are designed to perform a specific task, and be called anywhere in the throughout program. They can enable reusable code across your Lua program, which reduces the duplication of code. Functions have the attributes to values such as strings, numbers, etc, which can be stored in variables.

Functions are defined with the function keyword followed by the identifier of the function. The identifier of function follows the same rules as the naming convetion of variables. Afterwards, the calling operation () to declare with or without the given parameters. With the function body for the code to execute when called, along with the end keyword to mark the end of a block of code.

Since functions are values that a variable can hold, the local keyword can be optionally used here. This is because we're using a syntactic sugar when defining a function. And it is always recommended to make a local type, to improve performance and stuff.

Warning

Just in case, if you decide to declare a local type on callbacks it will not work properly. So please don't do it; it's stupid.

Syntax:

Syntactic Sugar Syntax:

function name(parameter1, parameter2, parameterX)
     -- function code
end

Non-Sugar Syntax:

local name = function(parameter1, parameter2, parameterX)
     -- function code
end

Example:

local function hello()
     debugPrint('Hello Function')
end

Calling

To call a function, get the function's said identifier, followed by the calling operation () for the arguments to be passed, if the function has parameters. If the calling operation is not present for some reason, it will return the memory address of the given function; Example: function: 0x5616d89c0770.

Tip

Functions are hoisted; once declared, the function is moved to the top of the scope before code execution. This means that you can call a function before the line of code that is declared in. This will not work if it is declared with the local keyword.

Example:

local function hello()
     debugPrint('Hello Function')
end

function onCreate()
     hello() --> Hello Function
end

When calling a function most of the time it will include the calling operation (). However there is a special rule for this, if there is only one argument to passed and it's either a literal string or a table constructor. Then the calling operation () is optional to use here, only requiring a space. Useful in some cases due to looks or for named arguments when calling a function for organization purposes.

Example:

function onCreate()
     debugPrint "Wow, so cool"     --> Wow, so cool
     debugPrint {3.14, 3.14, 3.14} --> [3.14, 3.14, 3.14]
end

Parameters

Parameters are special types of variables that are located inside the calling operation () of the given function. Since they're variables locally inside a function, they hold any value you could use a indexing access operation for tables, seen below or calling operation for functions. Each parameter must be separated by a comma , character if there are two or more of them. Their main purpose is to add more functionality to the given function for any arguments to be passed on.

Note

The word parameters and arguments are used interchangeably but they're not the same. Parameters are a special variable in a function definition, while arguments are the values to be passed on the parameters.

Example:

local function setPos(obj, pos)  -- concatenates setProperty x and y
     if pos[1] ~= nil then       -- makes pos parameter acts like a table
          setProperty(obj..'.x', pos[1])
     end
     if pos[2] ~= nil then
          setProperty(obj..'.y', pos[2]) 
     end
end
     
function onCreatePost()
     setPos('boyfriend', {100, 500}) -- Changes the position to x = 100 and y = 500
end

Lua adjusts the number of arguments to the number of parameters, as it does in a multiple assignment. Any extra arguments that are not assigned to any parameters are thrown away. If a parameter doesn't receive any arguments it will recieve a nil value.

Example:

local function choose(a, b)
     debugPrint(a or b)
end

function onCreate()
     choose(3)       --> 3 -- a = 3, b = nil
     choose(3, 4)    --> 3 -- a = 3, b = 4
     choose(3, 4, 5) --> 3 -- a = 3, b = 4   (5 is discarded)
end

Special Types

Variadic

Variadic functions (also called vararg functions) are a special type of function that accepts the number of arguments. It is indicated by a ellipsis character ... at the end of its parameter list. The number of arguments from the ellipsis character ..., will return multiple results. So it's recommended to contain it inside a table constrcutore {}; Example: {...}.

Example:

local function average(...)
     local sum = {...}
     local result = 0
     for i = 1, #sum do
          result = result + sum[i]
     end
     return result / #sum
end

function onCreate()
     debugPrint(average(1, 2, 3))                            --> 2.0
     debugPrint(average(45, 32, 29, 34, 23, 12))             --> 29.166666666667
     debugPrint(average(43, 91, 23, 54, 38, 23, 12, 90, 34)) --> 45.333333333333
end

Anonymous

Anonymous functions are a special way to declare a function. It doesn't include any identifiers, it only include the start and end with the function and end keywords, with some parameters if it includes one. This is only used for callbacks for specific built-in functions or a specific parameter requires a function to execute.

Example:

function onCreate()
     createTimer('timer', 3.0, function() -- anonymous function at use
          debugPrint('You\'re too slow!') --> 3.0
     end)
end

local timers = {}
function createTimer(tag, timer, callback)
     table.insert(timers, {tag, callback})
     runTimer(tag, timer)
end
     
function onTimerCompleted(tag, loops, loopsLeft)
     for _,v in pairs(timers) do
          if v[1] == tag then v[2]() end
     end
end

Modules

Modules are a collection encapsulate data mostly variables and functions. Which uses a table to wrapped around the functions and variables within, it acts as the namespace. This is pretty useful because it avoids duplication of code by creating a reusable library code across every Lua script. And helps organization of code to maintain your little code base of yours. Lua offers a built-in modules in their language, which are: string, table, and math.

A simple way to create your own modules, we use tables as I mentioned before. You declare local variable that holds a table, which acts as a prefix for each object in the module. With each objects inserted into the table, as seen below. Followed by the return statement, returning the table at the last line of code.

Important

This should be in a separate Lua file, and it should located where this file isn't executed.

Example:

local myModule = {} -- table to contain code, important

myModule.red   = 'ff0000'     -- variables
myModule.green = '00ff00'
myModule.blue  = '0000ff'

function myModule.isEven(num) -- function; same as "myModule.isEven = function() .. end"
     return num % 2 == 0
end

return myModule -- returning the table, important

After you created your own modules, you want your module to import into your Lua scripts. It offers a higher-level function to load and run libraries, called the require() function, it returns a table from the given module. To use it make a local variable at the top of the code, with a require() function. The argument it should receive is the path to the module starting outside the mods folder. You could use the slash character / or a period character . as a separator.

Example:

local mod = require 'mods.scripts.modules.test_modules' -- imports the module

function onCreate()
     debugPrint(mod.red)        --> ff0000
     debugPrint(mod.isEven(23)) --> false
end

Path Reference:

mods
└─scripts
  ├─modules
  │ └─test_modules.lua
  └─script.lua
Clone this wiki locally