An ultra-fast path to 2D gaming...
Lua has a mix of C-like and Pascal-like syntax.
Lua is dynamically typed (like JavaScript).
Spaces don't matter
Linebreaks don't matter
Indentation doesn't matter
No semicolons
On a given line, any text to the right of -- is considered a comment
123 and 0.456 are numbers.
Lua doesn't make a distinction between integer and real numbers.
Mathematical expressions +, -, * and / can be used on numbers.
> print(2+2) 4 > print ( 5 / 2 ) 2.5
true and false are booleans.
==, >, <, >=, <= are comparison operators.
~= is "not equal" operator (instead of !=).
There are also: and, or, not.
> print(5 >= 3 and not (3 < 0)) true > print(2.5 == 2) false
Strings represent a sequence of characters.
They can be enclosed in " (double quote) or ' (single quote) symbols (Choosing one, the other won't be considered a control symbol).
Escape symbols is done with \. Concatenation operator is .. (instead of + in some languages).
> print( "I am printin' \"My first string\"\non two lines" ) I am printin' "My first string" on two lines
Numbers are automatically treated as strings when concatenated, but other types (such as the boolean (5 == 0) in the example below) are not - use tostring on them.
> print( "This number is " .. 5 .. " and it equals zero: " .. tostring(5 == 0)) This number is 5 and it equals zero: false
nil (like null in many languages) means nothing. And equals nothing except itself.
Tables are ubiquitous in Lua.
A table is an array and a hashmap (dictionary) at the same time.
It is an ad hoc data structure.
An empty table is defined like this: {}.
Table keys can be of any type - integer, string, boolean or even another table.
> x = {} -- Wow, we defined our first variable! Yes, it is simple like this. > x[1] = "our first item" > print(x[1]) -- This is how we get a value by key from the table our first item > x["wm"] = "awesome" > print(x["wm"]) awesome
You can define a table and some initial key values simultaneously.
This is done like: y = { key = "somevalue", anotherkey = "anothervalue" }.
Comma is a separator here.
Only string keys (without quotes) are supported this way.
Lua offers one nifty mechanism for tables - you can access the values by the string key with following syntax: table.key. This creates an illusion of a data structure.
> x = {} > x.color = "white" -- Same as x["color"] = "white" > print(x.color) white > x.wm_langs = { xmonad = "Haskell", awesome = "Lua" } > print(x.wm_langs.awesome) -- Same as x["wm_langs"]["awesome"] Lua
If table doesn't have any value for the given key it means that the value equals nil.
> x = {} > print(x.blahblah) nil
You can initialize tables without specifying keys, then it will act as an array with values mapped to number keys.
> x = { "first", "second", "third" } > print(x[2]) second > print(x.2) -- No, no! Only string keys can be referenced like this! stdin:1: `)' expected near `.2' > print(x["2"]) -- 2 and "2" are not equal, of course nil
We will talk about functions later, now you should know, that any function can be assigned to a variable, passed as an argument or be returned from another function.
> ourfunction = print > ourfunction(2+2) 4 > get_length = string.len > ourfunction(get_length("some string")) 11
Lua is dynamically typed.
That means that you don't have to define the type explicitly - any variable can have any type.
Until variable gets declared it has the value nil.
To declare a variable just assign value to it.
> print(a) -- a wasn't declared yet nil > a = 42 > print(a) 42 > a = "the answer is " .. a > print(a) the answer is 42
Whenever you assign value to a variable, it becomes visible to the whole environment.
It becomes global (you can avoid it by using modules)
To keep your variables inside use the keyword local.
With local your variable will be visible only to the block (function, control structure, file) where it is defined.
> a = 42 > if a == 42 then -- If you press "Return" here, the next line will be >> local a = 10 -- preceeded with >>. This means that you are currently >> print("Inside: " .. a) -- inside the block (in this case, if..then block) >> local b = 100 >> end Inside: 10 > print(a) 42 -- See, local binding replaced a with 10 only inside the block > print(b) nil -- And the variable b was never globally declared
In Lua you can assign many values to many variables at the same time. It looks like this:
> a, b, c = 1, "and", 2 > print(a..b..c) 1and2 > a, b, c = 1, "and" > print(c) nil -- c hadn't got its value pair, so it was assigned to nil > a, b, c = 5, "and", 6, "and", 7 > print(a..b..c) 5and6 -- all unused values just went to Limbo
The syntax is simple: if condition then code else code end.
> food = "beans" > if food == "cake" then >> print("Yummy!") >> else >> print("Ew, I won't eat that!") >> end Ew, I won't eat that!
> under_attack = true > if under_attack then -- Booleans can be used like this in conditions >> print("Alarm!") >> end Alarm!
If you want to analyze more conditions, use elseif:
> n = -42 > if n > 0 then >> print("Positive") >> elseif n < 0 then >> print("Negative") >> else >> print("Zero") >> end Negative
Has the following syntax: while condition do code end.
> i, r = 0, "" > while i < 10 do >> r = r .. i >> i = i + 1 >> end > print(r) 0123456789
To loop through a range of numbers use the folowing construct:
for var = start_num,end_num do code end.
> r = "" > for i = 0, 9 do >> r = r .. i >> end > print(r) 0123456789
Lua allows you iterate through a table with the following syntax:
for key_var, value_var in pairs(table_name) do code end.
> a = { red="#FF0000", yellow="#FFFF00", white="#FFFFFF" } > for name, color_code in pairs(a) do >> print(name .. " is " .. color_code) >> end yellow is #FFFF00 white is #FFFFFF red is #FF0000
You can iterate through an "array" with ipairs.
In this case the order is guaranteed.
> a, caesar = { "veni, ", "vidi, ", "vici" }, "" > for i, v in ipairs(a) do >> caesar = caesar .. v -- We just don't use the key, only value >> end > print(caesar) veni, vidi, vici
The basic syntax for defining a function is: function_name = function(arguments) code end.
To return the value from a function use the keyword return.
> sum = function(a,b) return a + b end > print( sum(2,2) ) 4
If you don't supply some arguments to a function, then they will just be assigned to nil.
> print_three_args = function(a, b, c) >> print("First: " .. tostring(a)) -- We use tostring() here because >> print("Second: " .. tostring(b)) -- nil is not automatically cast >> print("Third: " .. tostring(c)) -- when concatenated >> end > print_three_args(10,20) First: 10 Second: 20 Third: nil
The function can return more than one value at once.
You need to use multiple assignment to get all result values.
> sum_and_diff = function(a, b) >> return a+b, a-b >> end > x, y = sum_and_diff(5,3) > print(x, y) -- print() can actually handle more than one argument. 8 2 -- It prints them separated by tab.
There is a more convenient way to define functions: function function_name (arguments) code end
> function doubler (x) >> return x * 2 >> end > print( doubler(42) ) 84
In conditions nil always evaluates to false.
It allows to do such witty tricks:
> f = io.open("foo.txt") -- Trying to open some file. If the file exists, than > if f then -- variable f will contain some table, else f will be nil. >> print("File exists") >> else print("File not found") end File not found
> function multiplicator (x, y) >> y = y or 2 -- If y is nil, then it will be assigned to 2 >> return x * y >> end > print(multiplicator(10, 3)) 30 > print(multiplicator(10)) 20
PHEW....
Create a main.lua file inside a dir of your choosing...
Fill it with the code below:
function love.draw() love.graphics.print("Hello World", 400, 300) end
This function gets called only once, when the game is started, and is usually where you would load resources, initialize variables and set specific settings. All those things can be done anywhere else as well, but doing them here means that they are done once only, saving a lot of system resources.
function love.load() image = love.graphics.newImage("cake.jpg") local f = love.graphics.newFont(12) love.graphics.setFont(f) love.graphics.setColor(0,0,0,255) love.graphics.setBackgroundColor(255,255,255) end
This function is called continuously and will probably be where most of your math is done. 'dt' stands for "delta time" and is the amount of seconds since the last time this function was called (which is usually a small value like 0.025714).
function love.update(dt) if love.keyboard.isDown("up") then num = num + 100 * dt -- this would increment num by 100 per second end end
Returns the time between the last two frames.
dt = love.timer.getDelta( )
function love.draw() love.graphics.draw(image, imgx, imgy) love.graphics.print("Click and drag the cake around or use the arrow keys", 10, 10) end
love.draw is where all the drawing happens (if that wasn't obvious enough already) and if you call any of the love.graphics.draw outside of this function then it's not going to have any effect. This function is also called continuously so keep in mind that if you change the font/color/mode/etc at the end of the function then it will have a effect on things at the beginning of the function. For example:
function love.load() love.graphics.setColor(0,0,0) end function love.draw() love.graphics.print("This text is not black because of the line below", 100, 100) love.graphics.setColor(255,0,0) love.graphics.print("This text is red", 100, 200) end
This function is called whenever a mouse button is pressed and it receives the button and the coordinates of where it was pressed. The button can be any of the constants. This function goes very well along with love.mousereleased.
function love.mousepressed(x, y, button) if button == 'l' then imgx = x -- move image to where mouse clicked imgy = y end end
This function is called whenever a mouse button is released and it receives the button and the coordinates of where it was released. You can have this function together with love.mousepressed or separate, they aren't connected in any way.
function love.mousereleased(x, y, button) if button == 'l' then fireSlingshot(x,y) -- this totally awesome custom function is defined elsewhere end end
This function is called whenever a keyboard key is pressed and receives the key that was pressed. The key can be any of the constants. This functions goes very well along with love.keyreleased.
function love.keypressed(key, unicode) if key == 'b' then text = "The B key was pressed." elseif key == 'a' then a_down = true end end
This function is called whenever a keyboard key is released and receives the key that was released. You can have this function together with love.keypressed or separate, they aren't connected in any way.
function love.keyreleased(key, unicode) if key == 'b' then text = "The B key was released." elseif key == 'a' then a_down = false end end
function love.focus(f) if not f then print("LOST FOCUS") else print("GAINED FOCUS") end end
This function is called whenever the user clicks off and on the LÖVE window. For instance, if they are playing a windowed game and a user clicks on his Internet browser, the game could be notified and automatically pause the game.
function love.focus(f) gameIsPaused = not f end function love.update(dt) if gameIsPaused then return end -- The rest of your love.update code goes here end
This function is called whenever the user clicks the windows close button (often an X). For instance, if the user decides they are done playing, they could click the close button. Then, before it closes, the game can save its state.
function love.quit() print("Thanks for playing! Come back soon!") end
special thanks to awesome wm wiki and love2d wiki (did you expect me to write all these alone?)
twitter: @tehn00b