Performance: Tilemaps in Löve with spritebatch

A usual pattern in 2D games is the use of tilemaps. In Löve you can implement those in a variety of ways. In this article I want to compare tilemap implementations in Löve 0.9.1 using spritebatches.

I will use this to create an ascii display.

Screenshot 2014-10-30 15.01.44


I will use the following code to measure the performance. It is an extended example from kikitos time function. It uses os.clock to measure the time before the execution and again after the execution.


   local last

    return function(title, f, n)
        if title == "clear" then last = nil; return end
        local n = n or 100000
        local startTime = os.clock()
        for i = 1, n do
        local endTime = os.clock()
        local delta = endTime - startTime
        if not last then last = delta end
        print(title, delta, (delta) - last)
        last = delta


We will generate a spritebatch with a tilesheet image(aka texture atlas) and use the spritebatches add/set method to change the content. The spritebatch will have NxM size. I used Alloy_curses_12x12 from the dwarf fortress tileset repository.

   local img ="Alloy_curses_12x12.png")
    local spritebatch =, 87*25, "stream")
    local quads = {}
    for x = 0, 255 do
        local i,j = 1+(x%16), math.floor(x/16)
        quads[x] =*12, j*12, 12, 12, img:getWidth(), img:getHeight())

We can also use the bind and unbind function on the spritebatch to bind the spritebatch into memory before we loop through the whole display grid.

Luajit Tables

We need two arrays: one to store the id and one to store the ascii value of the cell. Map is our display grid and idmap will store the id returned by adding the cells.

   local map = {}
    local idmap = {}
    for i=0,86 do
        map[i] = {}
        idmap[i] = {}
        for j=0,24 do
            map[i][j] = 68
            idmap[i][j] = spritebatch:add(quads[map[i][j]], i*12, j*12)

   local random = math.random
    time("spritebatch, lua table", function()
        for i=0,86 do
            for j=0,24 do
                map[i][j] = random(255)
                spritebatch:set(idmap[i][j], quads[map[i][j]], i*12, j*12)
    end, 1000)

FFI Arrays

We use the functions to generate a 2 Dimensional uint8_t array for the character display grid and uint16_t for the id grid.

   local ffi = require "ffi"
    local map ="uint8_t[87][25]")
    local idmap ="uint16_t[87][25]")

    for i=0,86 do
        for j=0,24 do
            map[i][j] = 68
            idmap[i][j] = spritebatch:add(quads[map[i][j]], i*12, j*12)

    local time = require "time"

    time("spritebatch, ffi array", function()
        local random = math.random
        for i=0,86 do
            for j=0,24 do
                map[i][j] = random(255)
                spritebatch:set(idmap[i][j], quads[map[i][j]], i*12, j*12)
    end, 1000)


Using Luajit tables is a lot faster than using FFI arrays:

spritebatch, ffi array 2.13035 0 spritebatch, lua table 0.577013 -1.553337

image (2)

FFI Arrays are a lot slower, so you should stick to tables if you want to draw tiles fast.

Slime explains: “The FFI array is probably slower because the loop it’s used in can’t be compiled by the JIT (since C API functions – all of LÖVE’s API, for example – prevent JIT compilation for the block of code they’re called in.)”

One more thing for spritebatch

It’s probably a good idea to only use spritebatch:set when something has changed. You can do this by having two map tables. Check if the map table is different than the cache table and only then set the spritebatch tile.

    for i=0,86 do
        for j=0,24 do
            if map[i][j] ~= old[i][j] then
                old[i][j] = map[i][j]
                spritebatch:set(smap[i][j], quads[map[i][j]], i*12, j*12)

I created an example lua file that can be used as a very simple base to render roguelike ascii games:gist. But of course this can be used for any other tile based game too.


Orcish Inn is an orc tavern simulation game. You raise crops, brew beer, create your tavern and serve your orcish guests. My name is Steven Colling, I’m from Germany and I create this game on my own with the help of Tilmann ‘headchant’ Hars, who is responsible for sound effects and music. I enjoyed farming and business simulation games as I was a child and I want to share my passion for calm and deep, strategical experiences.

more info

I am excited to be contributing the music and sounds to this!

Links: Vote on Steam Greenlight here Article about Orcish Inn by Kotaku Support the developer on epocu or patreon Follow Steven on twitter

Released: Totem’s Sound

Screenshot 2014-09-21 12.11.23
After 12 month of work I finally finished Totem’s Sound! I am also happy to tell you that it is available for free to download.

Head on over to to download a copy!

It was a great journey for me and I want to thank for getting me on board for this one. The game is also playable at the jacobsen exhibition of the Ethnologische Museum in Dahlem. A big thanks to everyone who worked on this one with me!

(Game-)ideas for the Apple Watch

I don’t know if I like this new device but it certainly can have some great uses. Most of these are small and based on the actuator in the watch.

1) Zitchtap:
Play together with a friend anywhere. Everytime you see a dog(cat, or something) you tap your watch and get a point.

2) Clickwrist
Never miss a beat again by syncing a clicktrack to your wrist.

3) Marco Polo / Hide and Seek
Actuator gets more intense/faster when near another player.
=> could also be used to enhance geocaching?

4) Cookieclicker client
Something like a clicker/incremental game for the wrist.

You got any ideas for this? Leave a comment.

Text Games: Short? Simple?

It kinda bothers me that a lot of the text based(tm) games today need to be short. But I don’t want (as in: I’m almost incapable to read!) to read a whole bunch of text so it must be broken up in very small pieces.

In a conceptual artistic context like in climbing 208 feet up the ruin wall by Porpentine or Capsule by Paperblurt there are hardly ever more than 6 lines of text and oftentimes less. This is effective: I read all text that is shown. I even can cope with the occasional wall of text if the game eases me into it. The text is also written in a big font.

Inklewriter might be another example: The presentation makes it easy to read the text and to play the game without getting tired too fast.

So we can’t make games with a lot of text? Or is it just a matter of breaking down the text?

Let’s derive from the current situation. I think it’s time for a manifesto*.

A Manifesto of Text Games(tm)?

  1. Make Text Games
  2. Text Games are made of chunks
  3. Chunks should be as short and simple as possible
  4. Chunks should convey something at first glance
  5. Hide Chunks and Use paging to create shorter Chunks

So we all know that simplicity and complexity somehow are opposite to each other but I am a strong believer that we can tell big stories and have great interaction if we follow the manifesto rules. Or maybe I’m wrong, who knows?

(tm): meaning games where you have to read words of a language as opposed to something like dwarf fortress

  • It’s not really time for a manifesto

LD30: Annex Kharon

Screenshot 2014-08-25 01.12.50


The Annex Kharon got lost in the STYX-Sector. The guanxi teleportal network is our only hope to gain resources and new tech. Survive long enough to find a way home through one of these wormholes.


The newest version will always be available at

Originally made for Ludum Dare #30.

(Download Compo Version Here)


Screenshot 2014-08-25 01.12.59

Screenshot 2014-08-25 01.13.28

Screenshot 2014-08-25 01.14.11

Ludum Dare #30: Final Round Ideas

Here are some quick game ideas for the LD final round themes:


Match-3 game with alchemical symbols, target: match to philosophers stone

Another World

Create planet resorts to welcome star travellers on there vacations.

Break The Rules

Not-game where you have to dance to arrythmic music.


“Battle of the wizards”-style game but in cyberspace with hackers

Choose A Path

Drunk Driving simulator

Connected Worlds

You want to make tea but the sugar is empty. Astroid-hike to your neighbors planet to ask for some

Day and Night

post-apocalyptic exploration in a desert, cold and warm balancing

Destroy The System

Android App: Everytime you drop your phone you get 100 Points, international leaderboards and local multiplayer

Don’t Stop Moving

Collect all 140 feet and battle against other feet-wearers

Do No Harm

FPS in \insert war here, twist: you are a pacifist


Blocks are people and can be commanded(flocking), built fortresses to protect


Gardening simulator


QWOP-style: wire different electronics

Lost In Space

Candybox/Populous crossover

No One Can See You

Puzzle Platformer with 2 modes: invisible and not invisible

Randomly Generated

CYOA Short Story generator

Strength In Numbers

Roguelike only with numbers instead of @

You’re Not Supposed To Be Here

Glitch-game where you have to get outside of a area

You Are Already Dead

Beach volleyball with angels in heaven

You Must Leave It Behind

Shopping-game where you have to choose between different items, example: something sustainable(long term, slower, more expensive) and something fun (short term, fast, cheaper), you then have to place the stuff in your house, which gets filled up, either way: you will just die in the end


Soon for Android and iOS.

Stonedraft is a thaumarchaeologic game about raising pillars of stones from ancient times.


Dig down 16000 levels of earth to find the mysterious buried stone – the batelum. On your way down, free the creatures embedded in boulders and make them your friends or enemies. Collect resources, open secret treasures and upgrade your stone sorcery.

Screenshot 2014-07-05 09.41.37

Based upon the LD29 Entry Kinetectonic:

“Very very fun game. Best game I’ve played yet!” bzizizi

“I loved this game. Simple, to the point, but still deep due to upgrades.” josefnpat

“5* everywhere! SO ADDICTIVE! I love you.” Pitoum

PFXR is back up

To popular demand my little weird sprite generator is back up on:

Screenshot 2014-06-29 21.42.50

Forgot to put it back after the last relaunch. (still working on the frontpage!)

I hope to revisit the generator one day and make it a lot better. But for now, I would like to know what you guys think of it?