38
\$\begingroup\$

I have a C++ game programming book and it has a Lua section in it. I've started to read the Lua section, and it sounds interesting, but I can't determine the pros and cons of using Lua in my C++ game. The only benefit I can currently think of is that you can make some coding updates, via Lua, without having to recompile. Other than that, I can't think of anything. So what are the pros and cons of adding Lua to a C++ game?

Examples would be appreciated.

\$\endgroup\$
4

5 Answers 5

33
\$\begingroup\$

The only benefit I can currently think of is that you can make some coding updates, via Lua, without having to recompile.

Do not discount the utility of this so easily. You will never understand how productive you will be until you take away the recompilation step.

The "flow" is a fairly well-understood psychological concept when it comes to work. The flow is that feeling you get when you're focused on an activity, when you're analyzing and solving problems almost without thinking, etc. You are at your most productive when you are "flowing".

Compile times screw all of that up. It's hard to stay in the flow if you have even a 10-second compile between testing something.

When you are developing gameplay, what you usually have is a "tight loop". You have an idea, you code up a test to see if it works, and then you try it out. If it doesn't work, you modify it and try again. The "code-to-test" time is very important for maintaining flow. Getting it as small as possible is crucial.

What Lua (or any embedded scripting language) allows you to do is to test changes, not just without "compiling", but live in the game. Depending on how you build your game, you can run a command that will restart the game with new scripts without having to stop and reload data and so forth. Not only do you not have to recompile, you don't have to re-run.

The ability to do this, given the proper engine support, can dramatically increase productivity.


Another major benefit to scripting is the ability to just not care. If you've spent a long time writing C++, you would be amazed at how much time you spend over minutae. Where memory is deleted. Where this gets freed. Even if you're using shared_ptr everywhere, just the act of typing in all of those variable type names slows you down.

In a dynamically-typed scripting language, you don't have to care. Scoping is simple. Functions are first-class objects; you don't have to manually build functors. It is just so easy to do some things.

Now that does have negatives, if you're not a disciplined programmer. It's very easy to use globals in Lua (though there are ways to prevent that). Not caring means that you can be very sloppy when you code.

But then again, being very sloppy can have advantages.


Another upside of Lua is that it makes a nice data description language. Much like JSON is just a JavaScript file that builds and returns an array/table, you can make Lua scripts that return tables.

This is useful for configuration files; Lua's table format is a lot better than .ini formats. The format is still rather clean, compact, and extensible.

Oh, and it's still a Lua script, so it can perform actual logic. The downside of that is... well, it's a Lua script, so it can perform actual logic. That could be disastrous in game, since the user could potentially start screwing things up.

But actually, this is easily dealt with. Lua is designed for embedding, which means that isolation is actually quite easy. Indeed, a fresh Lua state provides nothing by default; you have to actually do something to expose even the most basic of the standard Lua libraries. File access, game-state access, etc, is all opt-in, not opt-out. And each Lua state is separate from each other one. The Lua state you use for AI scripts does not have to be the Lua state you use for config files.

I actually have some code that allows you to register many Lua standard libraries, but goes through and removes all file IO. Ultimately, the worst that a Lua script-based configuration file could do is cause your game to crash immediately upon running it, by running it out of memory. And since you're not sharing these config files manually, that wouldn't be much fun for a hacker.


I would say that the biggest downside of any scripting language is debugging. Most scripting languages do not have debuggers, and Lua is no different. Lua does have all of the tools one would need to build debugging tools. But it does not actually have a debugger built-in. You have to put one together. And that's going to require a reasonable degree of work.

Or you can make due with "printf debugging". It really depends on how much Lua code you write.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ flowing is not always a good thing; doing things automatically sometimes means not taking time to walk over design alternatives. \$\endgroup\$
    – lurscher
    Commented Oct 9, 2011 at 8:12
  • 10
    \$\begingroup\$ @lurscher: Design is what you do before you sit down to code. You should have worked all of those design alternatives out before you started writing, testing, and debugging your code. \$\endgroup\$ Commented Oct 9, 2011 at 23:32
25
\$\begingroup\$

Where I work:

Pros:

  • iteration time improvements. Our game is set up to poll a host filesystem for changes and automatically "slurp" in changes. (They only take effect at next file open, but in practice, that's a major improvement: reload the level, and your new lua changes come in immediately.)
  • console integration. Any debug functionality can be hooked to a traditional Quake-style console with a REPL. For internal builds we can even hook a lua REPL to a simple socket that speaks telnet, and we have network control over our game.
  • reduced api and lower learning curve. Nontechnical artists and designers can join in on some tasks that would be typically programmer-bottlenecked.
  • specialized static code analysis. It's easy to parse the output of luac -l and peek at the bytecode to do some analysis; it's also pretty easy to parse most lua source files, especially if you have a coding convention. We can enforce local convention. You can also look into metalua for even more power here.
  • error handling. If our API is crash-free, even if lua does something silly, we can catch it and recover using lua_pcall.
  • easy API extension. Writing a new function for the Lua <-> C++ API is not too hard. There are also packages that will help automate this.
  • simple source. Making changes to e.g. avoid floating point mathematics in the lua interpreter (important on some embedded platforms) or to optimize for particular systems is not too hard!
  • metatables. These are awesome. So much potential to do interesting things at runtime. We have "virtual tables" that actually have no contents and perform a lookup into a complicated data structure on the C++-side of our games.
  • coroutines. Being able to stop and resume e.g. AI behavior scripts is amazing. It takes a bit more savvy on the lua scripter's part, though -- we're still working on how to make this more "safe" with our engine.

Cons:

  • unpredictable GC. Tuning what our step should be changes drastically per game. Some work better with full GC every frame (small working set). Some work better with much smaller passes more infrequently. Note there's a lot of work in improving the GC on newer lua versions and in some patches (which you shouldn't be afraid to use!)
  • higher overhead. We keep a lot of our large data structures C-side in order to avoid per-table-entry memory overhead. C++, C, and assembly generally produce faster code. So it's kept to the 90% of the game engine that isn't performance critical, and occasionally we do migrate things from lua to C (or vice versa).
  • fragmentation. Perhaps the biggest issue on small memory systems. We usually use small object pools and a completely separate large object heap for lua. We put full GC passes in strategic points in the game. We unload scripts or throw away the lua_State entirely in some cases. And we still sometimes have issues. Tuning the sizes of the small object pools (they're fixed, for simplicity and lower overhead) and the size of the lua-specific large object heap can be a pain. But on systems larger than about 4MB, we have not yet bothered with the specialized heaps and pools.
  • lack of type safety. If you don't have a good static code analysis toolset built, you're going to fall back on a lot of runtime error checking (perhaps using __index and __newindex). It's better if you can catch errors at compile time. There are various things you can do to alleviate this.

Lua's highly recommended, just be willing to work with it a bit! You may also want to check out Squirrel, although I believe it has a smaller userbase.

\$\endgroup\$
1
  • \$\begingroup\$ I wish I could vote this up multiple times. Very comprehensive, very insightful, clearly structured. +1 \$\endgroup\$
    – Koarl
    Commented Mar 21, 2012 at 14:47
5
\$\begingroup\$

Actually there are 3 great advantages:

These factors allow you as a game developer to enable features that will speedup the development and increase the quality of your game.

For example:

  • You will be able to change your game logics simply by updating your game from a file or a network socket.
  • You can allow users to create their own scripts (for bots or mods)
  • Your game designers and artists will be able to update and tests parts of the game without having to use your compile tool set.
  • You will not have to recompile every time you change a few scripts.
  • You won't have to rewrite the entire game if you change platforms/engines/languages.
\$\endgroup\$
1
  • 1
    \$\begingroup\$ "You won't have to rewrite the entire game if you change platforms/engines/languages." Unless you change from Lua to some other language. And if you're writing your "entire game" in Lua, if you change engines, then that change has to be exposed to Lua (or you need some abstraction between Lua and the engine to hide the details). So I don't see how Lua helps in those cases. \$\endgroup\$ Commented Oct 9, 2011 at 6:07
3
\$\begingroup\$

From my experience, boiled down a bit.

Pros

  • Initial integration is really easy. Tools exist to help generate bindings, but the binding mechanism is so simple that you could write your own version thereof, with your own custom features, in no time
  • You get much faster iteration on game logic (assuming you implement runtime reloading)
  • You'll get a liberating environment to experiment in: you'll try out more things because the overhead for doing so drops significantly
  • Familiar syntax: for all its differences, you'd be hard pressed as a C programmer not to be comfortable in it within hours
  • Better separation of game logic to "engine": your engine becomes a service provider that has to expose a decent API to the Lua client. The language barrier makes you think about that more, instead of just reaching in there and fiddling a member variable

Cons

  • Lua memory management isn't ideal for games. You cope with it, you don't like it
  • Lua debugging is awful out of the box. You'll have to work to improve the experience
  • Keeping data in Lua means you'll need to debug in Lua: inspecting it from C will initially be tricky
  • Lua has a good amount of shoot yourself in the foot syntax, like all variables being global by default
  • Lua is a programing language, just like any other. Don't expect non programers to magically turn into programers just because you removed the compiler
  • Getting good at integrating and supporting Lua is a big chunk of work. Don't expect it to purr right out of the box. It's fair to assume that you'll actually have to amortize this cost over a few games

Final, personal, verdict: if you're building a decent sized game and don't already have a scripting language, then get Lua. It'll be worth it.

\$\endgroup\$
1
\$\begingroup\$

Garry's Mod is one example of a game that uses Lua and C++. They use Lua for all of the mods, which makes them much easier for people to make. C++ is used for all of the internals. The only con I can think of would be the fact that Lua is not as fast as C++.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .