Fandom

Pico-8 Wiki

Lua

162pages on
this wiki
Add New Page
Comments0 Share

Lua is a programming language designed primarily for embedded systems. It is popular in the video game industry as a language that can be embedded in a larger game engine.

Pico-8 implements a subset of Lua for writing game cartridges. Because it is a subset, not all features of Lua are supported. Most notably, Pico-8 does not include the Lua standard library, and instead provides a proprietary collection of global functions.

Features of Pico-8 Lua Edit

The following are the major language features of Lua as implemented by Pico-8.

Comments Edit

Pico-8 code comments are preceded by two hyphens (--) and go to the end of the line. They also support a multi-line syntax using double-brackets (-- ... ).

-- one-line comment
--[[ multi-line
comment ]]

Values Edit

Pico-8 supports these fundamental types of values:

  • Numbers, in the range supported by 16:16 bit fixed point (-32768.0 to 32767.99)
    • Number literals can use decimal (17.25) or hexadecimal (0x11.4000).
  • Booleans (true and false)
  • Strings
    • String literals can use single quotes ('hello') or double quotes ("hello"), and the quote character can appear in the string escaped with a leading backslash ("you said \"hello\", yes?").
  • Nil (nil)
  • Functions (see below)
  • Tables
    • Sequences, indexed from 1: x = {2, 3, 5, 7, 11}; x[1] == 2
    • Mappings: x = {a=1, b=2, c=3}; x.a == x['a'] == 1
    • Unset indexes evaluate to nil: x[0] == nil

As in Lua, all composite and custom data types are based on tables.

Arithmetic operators Edit

Pico-8 supports these arithmetic operators:

  • plus: a + b
  • minus: a - b
  • times: a * b
  • divide: a / b
  • modulo: a % b
  • exponent: a^b

Arithmetic operators take numbers as arguments and return a number.

Relational operators Edit

Pico-8 supports these relational operators:

  • less than: a < b
  • greater than: a > b
  • less than or equal: a <= b
  • greater than or equal: a >= b
  • equal: a == b
  • not equal: a ~= b; Pico-8 synonym: a != b

Relational operators take numbers as arguments and return either true or false.

Logical operators Edit

Pico-8 supports the following logical operators:

  • and: a and b
  • or: a or b
  • not: not a

In logical expressions, false and nil are false, all other values are true.

Logical expressions "short circuit," and stop evaluating expressions left to right as soon as the value of the expression is known. For example, foo() and bar() calls foo(), and only calls bar() if foo() returns true.

A useful equivalent of the "ternary operator" from the C language is a and b or c, which evaluates to b if a is true, or c if a is false.

String operators Edit

Pico-8 supports the string concatenation operator: a..b

a must be a string. b can be a string or a number (which is coerced into a string).

No other type of value can be concatenated with a string. You can use a logical expression to convert a boolean to a string:

print("a > b: "..((a > b) and "true" or "false"))
You can determine the length of a string using the sequence length operator (#):
x = "hello there"
print(#x)            -- 11

See also sub().

Assignment operators Edit

As in Lua, you can assign a value to a variable or table slot

myvar = value

Pico-8 adds shortcut assignment operators for the arithmetic operators, often found in other languages like C:

myvar += value       -- myvar = myvar + value
myvar -= value       -- myvar = myvar - value
myvar *= value       -- myvar = myvar * value
myvar /= value       -- myvar = myvar / value
myvar %= value       -- myvar = myvar % value

(There is no ^= assignment operator.)

Variables Edit

Pico-8 supports global variables accessible to the entire program, and local variables accessible only within the function where they are declared. If a variable is not declared as local, then it is global.

-- a global variable
player_pos = {20, 60}

function move_player(newx, newy)
  player_pos = {newx, newy}
end

function circumference(r)
  -- a local variable
  local pi = 3.14
  return 2 * pi * r
end

Caution: A mistyped variable name is often interpreted as a global variable with no value assigned, which evaluates to nil. Most uses of unexpectedly nil values result in a runtime error, but these are not always easy to find.

Functions Edit

A function is a collection of statements that can be executed by calling it. The behavior of a function can be parameterized, and a function may return a value as a result.

function distance(x1, y1, x2, y2)
  return sqrt((x2 - x1)^2 + (y2 - y1)^2)
end

Pico-8 includes many built-in global functions, such as sqrt() in this example. See APIReference.

If control reaches a return statement, then the function exits. If return includes a value, then the function call evaluates to that value. If control reaches the end of the function's statement block without seeing a return statement, then the function returns nil.

A function in Lua is a "first class" value, just like other values. A named function in the outermost block is equivalent to a global variable whose value is a function. A named function can also appear inside another function, which is equivalent to a local variable.

A function can omit the name if it is called right away or otherwise used as a value (an "anonymous function").

x = {2, 3, 5, 7, 11}
foreach(x, function(v) print(x^2) end)

Lua functions are lexically scoped.

Conditional statements Edit

The Lua if statement takes a condition and a block of statements, and executes the statements only if the condition is true:

if score >= 1000 then
  print("you win!")
  score = 0
end

An if statement can include any number of elseif sections to test multiple conditions until one is found true, and an optional final else section to evaluate if none of the conditions were true. The general form is:

if cond1 then
  ...
elseif cond2 then
  ...
else
  ...
end

Pico-8 extends standard Lua with an abbreviated, single-line if statement, differentiated by having parentheses around the condition and no then or end keywords. You may use else, but it must be on the same line. There is no support for elseif. Some examples:

if (cond1) print("cond1")

if (cond2) print("cond2") else print("not cond2")

while and repeat loops Edit

The while statement executes a block of statements repeatedly as long as a given conditional expression is true:

x = 0
while x < 5 do
  print(x)
  x += 1
end

The repeat statement executes a block of statements repeatedly until a given conditional expression is true:

x = 0
repeat
  print(x)
  x += 1
until x > 4

while does not execute its block if the condition is already false. repeat always executes its block at least once, then tests the condition.

The break statement anywhere in a loop terminates the loop immediately without testing the condition. If the loop is nested inside another loop, only the innermost loop is terminated.

for loops Edit

There are two kinds of for loops in Lua. The numeric for loop traverses a numeric sequence from start to end, using an optional "stride" (with a default stride of 1).

-- draws 16 color bars
for c=0,15 do
  rectfill(c*8, 0, c*8+7, 127, c)
end

-- prints 1, 3, 5, 7, 9
for i=1,10,2 do
  print(i)
end

The other kind of for loop is the "generic for." In Pico-8, this is most commonly used with the all() and pairs() built-ins for traversing tables:

tbl = {2, 3, 5, 7, 11}
for v in all(tbl) do
  print(v)
end

tbl = {a=1, b=2, c=3}
for k,v in pairs(tbl) do
  print(k.."="..v)
end

The generic for statement expects the "in" expression to return a special kind of value called an iterator. The built-ins all() and pairs() return iterators. For information on how to create your own iterators, see Iterators and the Generic for in the Lua manual.

As with while and repeat, you can use the break statement to terminate a for loop immediately.

Tables Edit

Tables are the primary composite data structure in Lua. They are used as containers, especially sequences (like lists or arrays) and mappings (also known as dictionaries or hashtables). Tables can be used as general purpose objects, and when combined with metatables (see below) can implement object-oriented concepts such as inheritance.

Mappings Edit

Fundamentally, tables are mappings of keys to values. Key-value pairs are unordered. You can construct a new mapping using curly brackets. For example:

x = {a=1, b=2, c="hello"}

Values can be accessed using bracket notation, where the key is an expression (tbl["key"]).

print(x["a"])              -- 1

x["a"] = 99
print(x["a"])              -- 99

If the key is a string using the characters of a Lua identifier (letters, numbers, underscore, and begins with a letter), then the value can also be accessed using property notation (tbl.key).

print(x.b)                 -- 2

x.b = 88
print(x.b)                 -- 88

Accessing an unset key returns nil.

if x.d == nil then
  print("x.d is nil")
end

Pico-8 provides the built-in pairs(), which iterates over all key-value pairs in a table.

for k,v in pairs(x) do
  print(k.." = "..v)
end

Sequences Edit

A sequence is a table whose keys are a sequence of numbers starting with 1. Lua offers special syntax and features so that sequences behave somewhat like lists or arrays in other languages.

-- constructor syntax for sequences
y = {2, 3, 5, 7, 11}

print(y[1])           -- 2
print(y[5])           -- 11
if y[0] == nil then
  print("y[0] is nil")
end

-- the sequence length operator
print(#y)             -- 5

for i=1,#y do
  print("y["..i.."] = "..y[i])
end

A table that is a sequence is allowed to have other keys. The sequence part consists of all numbered keys starting from 1 ascending up to the first unset (nil) key.

y = {2, 3, 5, 7, 11, 13, 17}
print(#y)             -- 7

-- disconnect the latter part of the sequence with nil
y[4] = nil
print(#y)             -- 3

-- the other elements are still there, they're just not counted
print(y[5])           -- 11

Pico-8 provides several built-ins that operate on sequences:

  • add() appends a value to the end of a sequence.
  • del() removes the first element of the sequence that equals a given value, shifting all remaining elements down by one index to keep the sequence intact.
  • all() iterates over all elements in the sequence.
  • foreach() calls a given function for each element in the sequence, passing the element as the sole argument to the function.

Methods Edit

A method is a function that is stored as a value in a table. Lua has special syntax for defining and calling methods that cause the table itself to be passed to the method as a parameter named self.

ball = {
  xpos = 60,
  ypos = 60
}

function ball:move(newx, newy)
  self.xpos = newx
  self.ypos = newy
end

print(ball.xpos)           -- 60

ball:move(100, 120)
print(ball.xpos)           -- 100

In both the definition and the method call, using the colon (:) instead of the dot (.) implies the self behavior. If you define the method as a simple property of the table, you must remember to explicitly mention the self argument. This is equivalent:

ball = {
  xpos = 60,
  ypos = 60,

  -- without the colon syntax, must mention self argument explicitly
  move = function(self, newx, newy)
    self.xpos = newx
    self.ypos = newy
  end
}

-- using the colon, ball is passed as self automatically
ball:move(100, 120)

-- using the dot, must pass self explicitly
ball.move(ball, 100, 120)


Metatables Edit

The metatable for a table defines the behavior of using the table as a value with Lua operators. You can customize a table's metatable to specify custom operator behaviors.

The most common use of metatables is to implement object-oriented inheritance by redefining the __index operator. The new definition tells Lua to check for a given property on a parent prototype object if the property is not set on the current object.

function myclass:new(o)
  o = o or {}
  setmetatable(o, self)
  self.__index = self
  return o
end

Pico-8 supports the setmetatable() built-in. It does not support other related Lua functions such as getmetatable().

See setmetatable() for more information, links to references, and a more complete example.

Coroutines Edit

A coroutine is a special kind of function that can yield control back to the caller without completely exiting. The caller can then resume the coroutine as many times as needed until the function exits.

Pico-8 supports coroutines using built-in global functions instead of Lua's coroutine library. See cocreate(), coresume(), costatus(), and yield.

See cocreate() for more information, links to references, and a complete example.

Differences from Lua Edit

Pico-8 does not include the Lua standard library. See Math for a description of the Pico-8 mathematical functions. See APIReference for a complete list of Pico-8 built-in functions.

josefnpat wrote a list of technical differences between Pico-8's Lua and the official Lua 5.2.

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.