Quick and Dirty Asset Caching

Posted on August 03, 2016 by Donny Lawrence

My love2d game has a lot of assets. When I first started writing it, I didn’t pay much attention to “best practices” when it came to performance. Eventually I started to try and optimize.

The Problem

One of the first things I noticed when reading the docs for love.graphics.newImage was this:

love.graphics.newImage warning

Apparently, love2d doesn’t automatically cache images if they’ve already been loaded once, instead opting to read from disk each time. That’s fine if your disk access speed is fast enough, but for those with slow computers, it causes the game to chug. I saw similar issues with other file loading methods like love.graphics.newFont. This seemed like an obvious thing to tackle in my project, and a solution ended up being pretty simple.

The Solution

Thanks to the power of Lua, I didn’t even have to rewrite any code in order to fix the issue. I just created a new small module that “overwrote” some of the built in asset loading functions.

I started it with this, which allowed me to safely overwrite the built in functions with my own, while still being able call the originals.

local new_image = love.graphics.newImage

I was then able to drop in my replacement. It first checks if the name of the image is not a string, in case I’m trying to make an image using ImageData. If it IS a string, and the image can’t be found in the cache, it loads it using the new_image function that is actually the original love.graphics.newImage. After that, it returns the image, simply grabbing it from the cache if it was already there.

local function newImage(name, ...)
	if type(name) ~= "string" then
		return new_image(name, ...)

	if cachedImages[name] == nil then
		print("Loading image " .. name)
		cachedImages[name] = new_image(name, ...)

	return cachedImages[name]

Finally, I pointed love.graphics.newImage at my newly created function. This made it so all of my existing code would automatically point to this new function.

love.graphics.newImage = newImage

This provided me with a large performance boost with very little work. I wrote similar functions that handled fonts as well, since they can be cached in a similar way. I have put up a gist here that contains the full module. All you need to do in order to use it is put require "autocache" at the top of your main.lua.

A full example, which offers a better look at the performance increase, can be found here.