-- simple one liner
--[[ multiline
comment ]]
In lua every variable is by default global, which is a historical decision. Nowadays this is considered bad practice (f.e. in moonscript everything is by default local).
In general you should always use local
. Same goes for functions, which you can
also declare as local.
local x = 4
y,z = 4,9
-- equal to
==
-- not equal to
~=
-- greater than
>
-- less than
<
-- greater than or equal to
>=
-- less than or equal to
<=
-- Addition
+
-- Subtraction
-
-- Multiplication
*
-- Division
/
-- Modulus
%
-- Exponent
-- Use the built-in `^` operator rather than the `math.pow()` function.
^
nil and false --> nil
false and nil --> false
true --> true
0 and 20 --> 20
10 and 20 --> 20
false
andnil
are distinct: false represents the logical false state, nil represents the absence of a value
local COLORS = {
BLUE = 1,
GREEN = 2,
RED = 3
}
-- the above is equivalent to
local COLORS = {
["BLUE"] = 1,
["GREEN"] = 2,
["RED"] = 3
}
-- reading the integer back
local color = COLORS.RED -- the same as COLORS["RED"]
Lua is descended from Sol, a language designed for petroleum engineers with no formal training in computer programming. People not trained in computing think it is damned weird to start counting at zero. By adopting 1-based array and string indexing, the Lua designers avoided confounding the expectations of their first clients and sponsors.
t = {}
t = { a = 1, b = 2 }
t = { ["hello"] = 200 }
-- arrays are also tables
array = { "a", "b", "c", "d"}
print(array[1]) -- "a" (one-indexed)
print(#array) -- 4 (length)
Every value in Lua can have a metatable
. A metatable is also a Lua table that
defines the behavior of the value under certain events. A group of related
tables can share a common metatable, which describes their common behavior; a
table can be its own metatable, so that it describes its own individual
behavior. Any configuration is valid.
Lua always creates new tables without metatables.
t = {}
print(getmetatable(t)) --> nil
We can use setmetatable
to set or change the metatable of a table.
t = {}
meta = {}
setmetatable(t, meta)
print(getmetatable(t) == meta) --> true
Have a look at this detailed list of operations controlled by metatables. By convention, all metatable keys used by Lua are composed by two underscores followed by lowercase Latin letters.
We will have a look at some of the operations in the following part.
This metamethod is triggered when the table itself is called as a function. It is the only metamethod that allows multiple results.
local meta = {}
function meta.__call(...) print("You called __call", ...) end
-- create a testobject
local t = {}
-- set the metatable
setmetatable(t, meta)
print(t()) -- You called __call table: 0x0112360f08
print(t("Apple")) -- You called __call table: 0x01093ec000 Apple
Reading the content of the table. Note that the action is only triggered if the corresponding key is not present in the table.
-- first we want to set the __index method
-- this method gets called with the corresponding table and the used key
local meta = {}
meta.__index = function(object, index)
print(string.format(
"the key '%s' is not present in object '%s'",
index, object))
return -1
end
-- create a testobject
local t = {}
-- set the metatable
setmetatable(t, meta)
-- read a non-existend key
-- table[key] gets translated into meta.__index(table, key)
print(t["foo"]) -- the key 'foo' is not present in object 'table: 0x600002e8d2c0'
Writing the content of the table. Note that the action is only triggered if the corresponding key is not present in the table.
-- first we want to set the __newindex method
-- this method gets called with the corresponding table and the used key
local meta = {}
meta.__newindex = function(object, index, value)
print(string.format(
"writing the value '%s' to the object '%s' at the key `%s`",
value, object, index))
return -1
end
-- create a testobject
local t = {}
-- set the metatable
setmetatable(t, meta)
-- write a key (this triggers the method)
-- table[key] = value gets translated into meta.__newindex(table, key, value)
t.foo = 42
Do not use pairs()
or ipairs()
in critical code! For the performance tests,
see here.
Try to save the table-size somewhere and use for i = 1, x do end
.
-- i is a local control variable
-- the loop starts by evaluating the three control expressions:
-- initial value, limit, and the step
-- if the step is absent, it defaults to 1
for i = 1,5 do
end
-- the step value can be negative
for i = 20,-20,-1 do
end
-- here the step value is also defined (= delta)
for i = start,finish,delta do
end
-- iterable list of {key, value}
for k,v in pairs(tab) do
end
-- iterable list of {index, value}
for i,v in ipairs(tab) do
end
repeat
until condition
while x do
if condition then break end
end
As mentioned in the upper code example, pairs()
returns key-value pairs, while
ipairs()
returns index-value pairs. Be aware that pairs()
and ipairs()
behave slightly different. The ordering is NOT guaranteed in pairs()
. If you
do not use any keys in your table, pairs()
and ipairs()
are identical. Best
explained with the following example:
animals = {}
animals[1] = "Frog"
animals[2] = "Sheep"
animals[3] = "Dog"
animals[4] = "Cat"
animals["Fish"] = "Fish"
animals[5] = "Monkey"
--[[ 1 Frog
2 Sheep
3 Dog
4 Cat
Fish Fish
5 Monkey ]]
for k,v in pairs(animals) do
print(k, v)
end
--[[ 1 Frog
2 Sheep
3 Dog
4 Cat
5 Monkey ]]
for i,v in ipairs(animals) do
print(i, v)
end
if condition then
print("right")
elseif condition then
print("could be")
else
print("no")
end
Returns the largest integral value less than or equal to x.
The function uses the xoshiro256**
algorithm to produce pseudo-random 64-bit
integers.
If no argument specified, then returns [0,1). If called with one positive argument n, then returns [1,n] If called with two arguments, then returns [m,n].
When called with at least one argument, the integer parameters x
and y
are
joined into a 128-bit seed. Equal seeds produce equal sequences of numbers. The
default for y
is zero.
-- use of a modulo
local i = a%2 -- if a=2 then i=0; if a=3 then i=1
You can use single or double quotations. In makes no difference.
With the unary prefix operator #
you can get the length of a string.
local name = "Peter"
local length = #name
print(length) -- 5 (number of bytes, each character is one byte)
v can be of any type and will be coverted into a string.
local number = 20
local string = tostring(number)
print(string) -- "20"
local name = "pablo"
name = name .. "the number two" -- the two dots are called the string concetenation operator
Returns a formatted version of its variable number of arguments following the
description given in its first argument. The format string follows the same
rules as the ISO C function sprintf
cpp printf. The only
differences are that the conversion specifiers and modifiers *, h, L, l, and n
are not supported and that there is an extra specifier, q.
local name = "Eric"
local age = 34
string.format("My name is %s and I am %d old.", name, age)
With the unary prefix operator #
you can get the length of a table.
local my_table = {2, 5, 10, 22}
local length = #my_table
print(length) -- 4
If you call for the length, it will return a border in that table. The border in
the upper table my_table
is 4 because it satisfies the following applied
condition:
(border == 0 or my_table[border] ~= nil) and
(my_table[border + 1] == nil or border == math.maxinteger)
Here some table examples:
-- sequence, because only one border (5)
local table1 = {10, 20, 30, 40, 50}
-- not a sequence, has two borders (3, 5)
local table2 = {10, 20, 30, nil, 50}
-- sequence with one border (0)
local table3 = {}
table.insert(t,21) -- append (--> t[#t+1]=21)
With this function you can find a value in a table and return the index
function tblFind(t,e)
for i, v in pairs(t) do
if v == e then
return i
end
end
end
This is a simple example of how to create a class in lua.
local enemies = {}
local enemy = {}
function enemy:new(o)
o = o or {}
self.__index = self
setmetatable(o, self)
return o
end
function enemy:update()
-- update enemy
end
function enemy:draw()
-- draw enemy
end
Alternatively, you can pass predefined variables to the new
class as follows:
function enemy:new(x, y, health)
self.__index = self
o = setmetatable({}, self)
o.x = x
o.y = y
o.health = health
return o
end
To create a new instance of the enemy, simple call enemy:new()
and add it to
your enemies array as follows:
table.insert(enemies, enemy:new(20, 40, 10))
To update and draw the enemies simple loop over it. You can also use ipairs
.
for k,v in pairs(enemies) do
v:update()
v:draw()
end