Tips and Tricks for LUA and Corona SDK Part 1

Starting from a suggestion of one of our viewers, we’ve decided to make a few posts about tips, tricks regarding LUA and Corona SDK, sharing some of our know-how. This first post will cover a bit of what we think are some of the simplest and easiest ways to start optimizing your code, while the next ones will go more over Ragdog Studios SRL coding style.

LUA is great for its simplicity, and Corona SDK delivers that same simplicity in a clean and robust API. Everything comes at a cost though, and so does our favorite SDK.

The communication between our LUA scripts and the underlying Corona engine is, by nature, much slower than the same code written, for example, written entirely in objC. Apart from having more layers of abstractions, there’s also the communication within our structure that takes its toll.
Without going into much details, you can think of LUA as an easier way to give instructions to the Corona engine. This also means that informations must be shared among LUA and the engine. Obviously our LUA scripts aren’t always communicating with it, and although it still takes more time to process than going full native, we can take advantage of these moments to gain that few milliseconds we might come in need of.

What this line does is quite obvious. It increases the x position of an object by 1 at every frame.
What’s not obvious is the process that happens behind the scenes.
When we write “self.x”, we’re actually asking the engine to provide us with the actual X position of the object. When we change the X parameter of an object with “self.x =”, we’re asking the engine to update that information regarding that specific object. These kind of operations that requires a share of information between LUA and the engine are much slower of the same operation (increasing of 1 a variable) all made within LUA.

Instead, here we declare a new variable, “currentX”, that will be used to store our initial “object.x”. Since we know that we only want to increase it of one until the end of time, by doing this we avoid one step, the “get” of the “self.x” value from the engine. We only “set” it.
This is obviously a simple example. In general you should not try to overcomplicate things, because it could lead to less flexibility, and that would probably be worst. But say you want even 30 objects moving on the screen at all times, it really helps to avoid “get” and “set” operations as much as possible.

This brings us to our next topic. Global variables. In LUA you have global, and local variables. The first ones are pretty cool. Once declared, a global variable will be readable in any one of your modules. If you need to share a variable from your main.lua file to your menuScene.lua file, you can easily do so with a global variable.
The downside to them, is that they are in general 30% slower to read than local variables. They’re really easy to use and they will simplify your life, but there are a few pointers that we usually keep in mind when going with them.

The first thing is the “_G.”, before the variable name. Each global variable gets automatically stored inside a LUA table called “_G”. This means that when you declare a global variable, you’ll also be able to access it like you normally would with a parameter inside a table.
We don’t know if the code we write will always be read just by us, or by new co-workers or even entirely different coders who now need to discover its secrets. We need to make sure that whoever gets our code, will be able to easily navigate it. Always using “_G.” in front of our globals really helps for that. No matter who, when they look at it, they’ll know it’s a global variable, probably declared in main.lua or in a specific external module.
Not only that, it also completely eliminates the problems that might arise when, by mistake, we use the same name of one of our global variables as a local variable name in a module. By writing “_G.”, LUA knows that we’re refering to our global variable, and not our local one. Obviously avoid naming them the same (:
In general, use global variables for data that you won’t need to update or read frequently. If you plan on doing that, make sure you localize it first.

If global variables are 30% slower than local variables, this means that local variables are 30% faster. Not only that, but local variables “closer” to the current scope are even faster.

Localize your functions, especially if they come from a global variable, or worst, as a parameters of a global table. If you use them frequently within the same scope (more than 1-2 times), localize them again inside of it.
We put the “math.random” function (notice we aren’t running it as “()” are missing, we’re only getting the function itself), inside our mRandom local variable. Then, since we call mRandom 5 times inside our enterFrame function (which is a new scope), we localize it again. Again, any little speed gain helps when working within a simplified environment, and making good habits of these procedures will definitely show its results on the long run.

It might seem a pain to follow these procedures, and someone might also be thinking “Why shouldn’t I use / instead of * ? If they put it in there, it’s cause it can be used!”, and that’s true. They put it there, because it can and in some cases should be used. But that doesn’t mean that it is the fastest option out there, and in some occasions, we need to squeeze every last drop out of our code. Try to find a balance between optimization and simplicity. If optimizing means making your code a mess, than it’s better not to do it all.

In our next post, a bit of insight on how we structure our code in a Corona SDK project, from config to modules.

1 Comment

  1. Absolutely brilliant! Such amazing tips from a great group of developers. Thanks for the article, it should definitely be one of the first logic’s taught in Corona SDK dev. I especially love how you reference the different layers of Corona SDK engine before you request is sent to the native code. Makes a ton of sense, and will prove to be invaluable to the Lua/Corona community. You set out some very clear patterns to follow to inprove your performance experience. ;)

    Look forward to reading about the RagDog approach methodology, and if you could, would be interesting to reference the movement from Actionscript 3/ Flash dev to Corona SDK, as I have the strongest feeling, your experience was groomed by Actionscript 3 and Flash game development. Correct me if I am incorrect ;)