- Introduction to lua
- Basic Setup
- Estrela for Luxinia
- Scenegraphs
- Scene Setup
- Models/Meshes
- Input handling
- Basic physics
- Physics surface properties
- Vehicle physics
- Using models
- Picking
- A Simple UDP Server
- GUI for the UDP Server
- Tetris attack clone prototype
- Stencil Shadows
- Sprite animation with matobject
- Project archives
- Estrela for Cg
- Specular mapping shader
- Material and Matobject
Variables
<< Commenting | Lua | Functions >>Variables represent a memory inside a program comparable to the our own memory.
Unlike in other progamming language, there's no need in lua to declare variables (but you can change this behaviour if you don't like it).
Simply use a variablename that you need:
Example:
myvariable="hello" print(myvariable) myvariable=123 print(myvariable+10)
Output:
hello 133
A variable in Lua is just a name, the type is set dynamicly to whatever you use the variable for. There are only 6 different types in lua:
- boolean (true or false)
- numbers (no matter with or without point etc.)
- strings
- tables
- threads (Co-routines)
- userdatas
nil. A variables that become nil will stop existing.
You have seen numbers and strings by now, let's take a quick look at the other types. Userdatas are dataelements that are created by the implementors side of Lua, so Luxinia for example.
Every object in Luxinia that you touch is a userdata value and most functions in Luxinia need a userdata value as argument. Userdatas can have metatables, but you cannot modify them directly. I will come back to metatables and what this means in a later tutorial, but not for now since metatables are an advanced topic.
Threads are coroutines in Lua. Coroutines can be created from functions in Lua and can be used for a multitasking like behaviour. Coroutines, once run, will run until they finish or a yield is called which then returns to the line where the coroutine was invoked. The function can then be continued at any time. Coroutines are usefull if you want to process something that takes long and you want to split this task up in several small parts that are processed frame by frame. This is needed if you want to show the user a loading screen telling him how much must be loaded for example.
Strings and numbers
Strings and numbers are very simple types and I don't need to explain much about it (although there's much more to be said about it, but I don't want to get this tutorial too long). Strings describe texts. A string can be of any length. Strings cannot be altered - you cannot change the value of a single sign in the string, you can only make copies. This is the reason why you shouldn't concatenate strings to longer and longer strings, since evertime a copy is made and that needs much memory and performance. Instead, you should push the strings in a table and calltable.concat. That will create one big string from all the entries in the table in an optimized way. It is often the case that beginners don't know this and wonder why their code is slow.
Numbers are describing numbers (surprise!), unluckyly, numbers in computers are somewhat limited in precission and "size". Numbers in lua are always floating point numbers. There are no integers (integers have always rounded values). If a function in luxinia says it wants an integer value or anything like that, just pass a number. The precission of numbers in lua are dependend on the way the programmers integrate lua, in our case we use the default type and that are double values (doubles are normally 64bit sized). Double values can become fairly large and offer a good precission. We decided to leave it this way although luxinia is using only 32 bit floating point precission.
Conversion
Numbers and strings are converted to each other if needed and if possible.Example
print("1"+"2"+3+4) print((1)..(2).."3")
Output
10 123
The numbers in the second line must be in round brackets, otherwise the compiler will complain about the numberformat.
However, it is often better to convert a variable into a string before using it as a string:
Example
x = 2 print(tostring(x))
Output
2
The other types cannot be converted into each other.
Naming variables
You can choose any name for a variable as long as it starts with a letter and doesn't contain special signs except underscores. Valid names are Watch out here that the names are case sensitive, soMYtable? is another variablename than mytable.
Invalid names are
- 42names
- my-bottom-line
Assigning values
As seen before, you can assign values to variables by using a equal sign:
hello = 3You can also assign multiple variables at once:
Example
a,b,c = 1,2,3
print(a,b,c)
Output
1 2 3
This looks strange to programmers that come from languages that are like C or Java. But it is usefull:
Example
a,b = 1,"hello"
a,b = b,a
print(a,b)
Output:
"hello" 1
We exchanged here the values of a and b without using a temporary variable.
What cannot be done is a usage like this: a = b = 3.
Scope
When a varible is initialized, it is per default stored in a global table that everyone can access (normaly).A scope is declared in different ways. We will just take a look at the do ... end case where the scope is limited from do to end
A scope is a kind of view: You can declare variables to be only "visible" within a certain range and that is your scope.
If you don't want to share a variable with other pieces of code, you need to declare the variable as local:
Example
do aglobalvalue = 3 local alocalvalue = 1 print("my local value: ",alocalvalue) do local aglobalvalue = 10 print("my global value, now local: ",aglobalvalue) end end print(aglobalvalue,alocalvalue)
Output
my local value: 1 my global value, now local: 10 3,nil
It is always a good idea to declare a variable as local. It allows a faster access on the value of the variable. It is also annoying if you pollute the global variable table with lot's of names that other parts of lua code are absolutly not interested in.
As you can see above, local variable names will not change global variables. They will coexist and you cannot access the global value with the same name, once you are using a local variable of the same name. But when the scope is leaved, the global value can be accessed again normally.
As said above, a do - end block is only one type of scope. There are other forms that provide their own scope.
Tables
Tables are the most important datastructure in Lua. You can imagine tables as real table where each line can by found by using a name or a number.This name can be of any type (strings, numbers, tables, coroutines, userdatas) and there is only one line per name, this is why this is often called 'key' - you can adress any value in a table if you got the right key. Let's do an example:
Example
mytable = {}
mytable[1] = "hello"
mytable[2] = "second table value"
mytable[249043] = "the key can be any value"
mytable["akey"] = "a key can be a string..."
mytable.anotherkey = "and can be adressed this way, too"
This is a simple table, initialized one by one. You could write it in a shorter form this way:
Example
mytable = {
"hello", "second table value",
249043 = "the key can be any value",
akey = "a key can be a string...",
anotherkey = "and can be adressed this way, too",
}
note that you can leave the last comma out, but it doesn't hurt if you write one. You will like this little feature once you generate Lua tables automated as strings.
Garbage collection
Lua implements a garbage collection, that means that if you "forget" a variable, it will be removed from the memory automaticly. Don't be afraid now - it won't collect your variables if you still need them.The garbage collection is done automaticly from time to time (it can be forced by calling collectgarbage()) and it will collect every variable that is no longer accessible.
For example:
mytable = {1,2,3}
mytable = nil
my2ndtable = {1,2,3}
backup = my2ndtable
my2ndtable = nil
The variable mytable cannot be accessed anymore since there's no other variable pointing to it. The 2nd table that was initialized is not removed since the backup variable is still pointing on it.
Even special cases like this are found and will be collected:
Example:
table1,table2 = {},{}
table1.tab = table2
table2.tab = table1
table1,table2 = nil,nil
Even though the tables are pointing at each other, the collector will recognize this and will collect it.
Values, pointers, references, adresses
A variable can hold a value, but the value can be of different type (seen above) - but not only in it meaning, but also in it's type of use.
Let's see
Example
a=1
b = a
a = 2
print("a = ",a,"b = ",b)
Output
a = 2 b = 1
That shows that we haven't changed the value of b by changing the value of a. This is the same for strings.
But it is different for tables:
Example
orig = {1,2,3}
table2 = orig
orig[1] = 7
print("table2[1] = ",table2[1]," orig[1] = ",orig[1])
Output
table2[1] = 7 orig[1] = 7
What happend here is following:
- A table is created in memory of the computer
- A variable named
origis pointing to the memory adress - The value of the variable
origis assigned to a variable namedtable2 - The value of the table at index 1 in memory is changed to 7
This mechanism has often different names like references or pointers, each one has different meanings in different programming language although the idea is the same: We use an address to a value, instead the value itself.
I will come back on that in the tutorial about functions.
