Important News: 26/10/2016 - Call for Presentations to Lua Devroom at FOSDEM 2017
Important News: 04/05/2016 - Community news #2
Important News: 11/12/2015 - Blog opening and contribution guide

An Introduction to Metatables

By Jeremy Clarke Jun 12 2016 13:06 General Reblogged Comments

Hi folks, this post aims to offer a clear introduction to the topic of metatables in Lua for those who are not yet familiar with them. I originally wrote this for the forums of PICO-8, a 'fantasy console' with limitations inspired by classic 8-bit computers, which uses a modified flavour of Lua 5.2.

Without further ado, let's go!

A table is a mapping of keys to values. They're explained quite well in the PICO-8 manual and the Lua reference manual so I won't go into more detail. In particular you should know that is just a nicer way of writing t["foo"] and also that t:foo() is a nicer way of calling the function

A metatable is a table with some specially named properties defined inside. You apply a metatable to any other table to change the way that table behaves. This can be used to:

  1. define custom operations for your table (+, -, etc.)
  2. define what should happen when somebody tries to look up a key that doesn't exist
  3. specify how your table should be converted to a string (e.g. for printing)
  4. change the way the garbage collector treats your table (e.g. tables with weak keys)

Point #2 is especially powerful because it allows you to set default values for missing properties, or specify a prototype object which contains methods shared by many tables.

You can attach a metatable to any other table using the setmetatable function.

All possible metatable events are explained on the lua-users wiki:
>>> list of metatable events <<<

which is, as far as I'm aware, the best reference for everything that metatables can be used for.

And that's really all you need to know!

Vectors Example

I'll now demonstrate how metatables could be used to make a "2D point/vector" type, with custom operators.

-- define a new metatable to be shared by all vectors
local mt = {}

-- function to create a new vector
function makevec2d(x, y)
    local t = {
        x = x,
        y = y
    setmetatable(t, mt)
    return t

-- define some vector operations such as addition, subtraction:
function mt.__add(a, b)
    return makevec2d(
        a.x + b.x,
        a.y + b.y

function mt.__sub(a, b)
    return makevec2d(
        a.x - b.x,
        a.y - b.y

-- more fancy example, implement two different kinds of multiplication:
-- number*vector -> scalar product
-- vector*vector -> cross product
-- don't worry if you're not a maths person, this isn't important :)

function mt.__mul(a, b)
    if type(a) == "number" then
        return makevec2d(b.x * a, b.y * a)
    elseif type(b) == "number" then
        return makevec2d(a.x * b, a.y * b)
    return a.x * b.x + a.y * b.y

-- check if two vectors with different addresses are equal to each other
function mt.__eq(a, b)
    return a.x == b.x and a.y == b.y

-- custom format when converting to a string:
function mt.__tostring(a)
    return "(" .. a.x .. ", " .. a.y .. ")"

Now we can use our newly defined 'vector' type like this:

local a = makevec2d(3, 4)
local b = 2 * a

print(a)      -- calls __tostring internally, so this prints "(3, 4)"
print(b)      -- (6, 8)
print(a + b)  -- (9, 12)

Pretty neat right?

Object Orientation

I mentioned that metatables can be used to define what should happen when a key lookup fails, and that this can be used to create custom methods shared by many tables. For example we might want to be able to do this:

a = makevec2d(3, 4)
a:magnitude()  -- calculate the length of the vector, returning 5

In Lua this is not always necessary, for example, we could define an ordinary function to do the job for us:

function magnitude(vec)
    return sqrt(vec.x^2 + vec.y^2)
magnitude(a)  -- returns 5

In fact, for PICO-8 I would recommend that approach, because it's as efficient as you can get, and it uses the least number of tokens (PICO-8 cartridges are limited in code size).

But I think it's educational to see how metatables can make it possible to use Lua in a more OOP style.

First off, we define all our methods in a table somewhere. Note, you can define them in the metatable itself (this is a common convention), but I'll put them in a different table to prevent confusion.

local methods = {}
function methods.magnitude(self)
    return sqrt(self.x^2 + self.y^2)

The __index property of a metatable is referred to when you try to look up a key 'k' which is not present in the original table 't'.

If __index is a function, it is called like mt.__index(t, k)
If __index is a table, a lookup is performed like mt.__index[k]

So we can add the magnitude function, along any other methods we may have defined, to all our existing vector objects by simply setting the __index property to our table of methods:

mt.__index = methods

And now, as we wanted, we can call a:magnitude()
Which is a shortcut for a.magnitude(a)
Which is a shortcut for a["magnitude"](a)

Hopefully given all this information, it's clear what's happening: We never defined a magnitude property in 'a', so when we try to lookup the string "magnitude", the lookup fails and Lua refers to the metatable's __index property instead.

Since __index is a table, it looks in there for any property called "magnitude" and finds the magnitude function that we defined. This function is then called with the parameter 'a' which we implicitly passed when we used the : operator.

Well, that's it from me! I hope somebody finds this post useful, and please let me know if there is something you don't understand, or something that I left out or could have explained better. If you'd like to see more examples of metatable usage and OOP, I recommend chapters 13, 16 and 17 of Programming in Lua.

Community news #2

By Etiene Dalcol May 04 2016 23:46 General Comments

Meet-ups and conferences!


luaconf logo



Featured Releases

Using Lua coroutines to create an RPG dialogue system

By Jeremy Clarke Apr 11 2016 07:31 Gamedev Reblogged Comments

Recently I've been working on an RPG with a friend, for whom coding is not their strong point. We're using the excellent LÖVE framework, so the whole game is written in Lua.

Scripting of dialogues, animations and in-game events is a hugely important aspect for any RPG, and I wanted to build a scripting system that's easy to use and doesn't require any knowledge about the rest of the game's engine, but is also powerful enough for me to extend with new functionality as needed. This post aims to show how a few simple Lua features can be combined to create a scripting environment that's pleasant to use.

First, let's take a look at the XSE language used in Pokémon modding, as this was probably my main point of inspiration. It has a very straightforward, imperative style, even though each instruction doesn't correspond to a single function in-game.

By this I mean, the whole game engine doesn't freeze just because you are talking to an NPC, however there are points at which the dialogue script cannot progress until the text animations have finished and the player has pressed the [A] button.

XSE Example

Another interesting tool is Yarn, a dialogue editor in which you connect nodes of text together to form complete conversations. It has variables, conditionals and custom commands which you can hook up to different parts of your engine to trigger animations and such. I'd say it's definitely worth checking out especially if you're using Unity or similar.

So how would we go about creating such a system in LÖVE without creating our own language or writing an interpreter for an existing language such as Yarn?

Part 1: Chaining Callbacks Together

The first thing we need is the ability to 'say' some text from inside a script, which boils down to setting a string and then waiting for the user to press a button before we resume execution of the script. The game should still be updating on every frame, even when text is being displayed.

In true JavaScript fashion, we could create an asynchronous API that looks a bit like this:

text = nil
callback = nil

function say(str, cb)
    text = str
    callback = cb

Our game logic & rendering code could look something like this:

function love.update(dt)
    if not text then
        -- player movement code

function love.draw()
    -- code to draw the world goes here

    if text then, 10, 10)

function love.keypressed(key, isRepeat)
    if text and key == "space" then
        text = nil
        if callback then
            -- execute the next part of the script

Then we could write a dialogue script that looks like this, potentially fetching it at runtime with a call to dofile() or something:

say("Hello there!", function ()
    say("How's it going?", function ()
        say("Well, nice talking to you!")

This kind of code grows unwieldy very quickly. It's confusing for non-coders and also error prone (many places to miss out a comma or a closing bracket). You could try some variations such as giving a name to each function, but it still turns out quite unpleasant to work with because managing all those functions gets in the way of what matters: writing good dialogue and scenes. At this point we'd surely be better off writing a Yarn interpreter or using some other existing solution.

But this is not JavaScript, and we can do better!

Part 2: Using Coroutines

For the uninitiated, coroutines are chunks of code that can be jumped to much like functions. A coroutine can suspend itself (yield) at will, returning to the point at which it was called. At a later stage, the program can jump back into the coroutine and resume where it left off.

I suppose this puts them in a sort of middle ground between functions and threads. They are more powerful than functions, but you still have to manage them explicitly - you can't just leave them running in the background to do their own thing. Typically they are used to break up an intensive task into small bursts, so that the program can still function as normal (receive user input, print to console, etc.)

Hang on a minute, doesn't this sound a lot like what we want from the dialogue scripting system? Executing a single line and then suspending the script while we give control back to the game loop?

Let's see how we could achieve the same result as Part 1, only using a coroutine instead of a chain of callbacks.

text = nil
routine = nil

function say(str)
    text = str
    text = nil

function run(script)
    -- load the script and wrap it in a coroutine
    local f = loadfile(script)
    routine = coroutine.create(f)

    -- begin execution of the script

The important difference here is the implementation of the say function. Instead of setting a callback for later use, we tell the current coroutine to yield. This means we can't call say directly from the main program, only from inside a coroutine. Also there is now a loader function which creates a new coroutine and tells it to run the script.

Next we need to rewrite love.keypressed to make it resume the coroutine on the press of the space bar.

function love.keypressed(key, isRepeat)
    if text and key == "space" then
        if routine and coroutine.status(routine) ~= "dead" then
            -- execute the next part of the script

And finally, we can write a script that looks like this:

say("Hello there!")                -- the script suspends once here
say("How's it going?")             -- it suspends again here
say("Well, nice talking to you!")  -- it suspends for the 3rd time here

Part 3: Sandboxing and Advanced Usage

If we declare a global variable, 'n', we can create an NPC that remembers how many times the player has spoken to it.

say("Hey kid, I'm Mr. Red!")

if n == 0 then
    say("I don't believe we've met before!")
    say("You have spoken to me "..n.." times!")

n = n + 1

It's great that this works, because it does exactly what you would expect and it's super easy to use. However, there are some problems.

If all the variables are stored in the global environment, we risk running into naming collisions which at best will cause scripts to behave incorrectly and at worst could replace key functionality and crash the game.

Additionally, having our game's state scattered across a ton of globals makes things very difficult when we want to think about serialising the gamestate to produce a save file.

Fortunately Lua makes it easy to swap out the environment of a function for any table, using setfenv in Lua 5.1 or _ENV in Lua 5.2 or greater. We don't need to change our scripts at all, we just need to make sure that they still have access to the say function, by placing it in their environment (the game table below).

game = {}

function game.say(str)
    text = str
    text = nil

function run(script)
    local f = loadfile(script)
    setfenv(f, game)
    routine = coroutine.create(f)

    -- begin execution of the script

It also might be helpful to have a script that is called once at startup, to initialise all the game variables to default values, or load them from a save file.

As far as animation goes, we can drop in a tweening solution like flux, along with a few helper functions which will allow us to pause the script until the animation completes.

game.flux = require "flux"

game.pause = coroutine.yield

function game.resume()

and then we could tween a character to x = 800 with a script like this:, 2.0, { x = 800 }):ease("linear"):oncomplete(resume)

which yes, is a mouthful for non-coders, and it introduces an asynchronous aspect back into the scripting API. We would probably benefit from a custom animation system that's more more tailored to our game, but this hopefully goes to show how easy it is to make scripts that can interact with any other part of the engine.

What Next?

I hope I was able to teach some interesting ideas here! I wanted to share this because coroutines are something I've known about for a while, but until now I've never had a good reason to use them. I would be interested to know which other languages can be used to create a system like this.

Here are some things you might want to do next, to create a more full-featured RPG engine:

  • Add lock() and release(), so it's possible to display text while the player is moving, or stop the player from moving even when there is no text.
  • Add an ask(str, ...) function whereby the player can choose from a list of options (e.g. yes/no)
  • Download a level editor such as Tiled, or create your own. Try attaching some scripts to game objects such as buttons and NPCs. Relevant tutorial on using Tiled with LÖVE
  • Create an easy-to-use animation system with commands such as 'face X direction' or 'move N steps'
  • Add character portraits so that the player knows who's speaking (this might require you to add an extra parameter to say() or some new functions)
  • Consider how you would go about handling save data. How to distinguish it from data which is part of the gamestate but does not need to be saved permanently?


Subscribe to Lua.Space by Email