I really should be talking more about the programming decisions in Dredmor, but for the most part the programming decisions in Dredmor are uninteresting. There are a few little bits of cleverness lurking under the hood – there’s some good stuff in the map generation system, and some good stuff in the load/save system – but for the most part, Dredmor’s programming isn’t particularily sophisticated or challenging. Instead, I’d like to talk about some technology decisions that didn’t work out.
In the engine that we’re putting together for the next game that we’re making, and for the game that we tried to make before deciding to finish Dredmor, we found ourselves needing a scripting language. Scripting languages are important for games: they form a divide between certain elements of game logic and the engine itself. They also make it harder (if correctly implemented) for a game designer – who may not be thinking as a programmer – to crash the engine or to introduce Exciting Behaviours into C++ code. We wanted a scripting language, and I shopped around looking for one.
For our first attempt at solving this problem, we decided to use Ruby. Ruby is a scripting language that now powers… well, a fair amount of the web… due to its elegant design and a little library called Rails that you might have heard of. Ruby has a lot to like about it. It’s a smart, well-designed language that comes with a good set of useful primitives. It supports serialization and reflection of objects out of the box, it has a number of useful string manipulation functions, and it has utility libraries for everything under the sun. It looked like a winner, and it came with some binding code to help you integrate it into your C code. The problem, then, was how to integrate it into C++? How do we get two object-oriented programming models to play nicely?
Integration, surprisingly enough, turned out to be a very pleasant experience. I started with some good hints from Gaffer and his Ruby wrapping classes, and ended up mangling the hell out of his library to add some features specific to our needs (like cross-platformness and transparent object serialization.) The part that I found particularily delightful about the experience is that Ruby can internally serialize classes – including new, exciting sorts of objects – as plaintext strings. This made it very easy to get Ruby playing nicely over a network.
So, why doesn’t Ruby work? Short answer: the garbage collector sucks.
Long answer: Ruby’s GC does not support asynchronous garbage collecting, or incremental garbage collecting. Instead, when the garbage collector runs – it *runs*. And by runs, I mean chugs. I hope that some day this will get fixed, and would fix it myself except that I don’t know enough about Ruby’s internal source code or how to write a garbage collector to attack the job. If anybody out there knows something about these two topics and wants to make Ruby’s GC useful for games, let’s talk.
What are we going to do next? I’m not sure. My occasional hackmaster buddy, Ryan C. “Icculus” Gordon (that’s a mouthful), suggested Lua. Everybody does Lua these days, and that’s both a good thing and a bad thing. I suppose it does what you want it to do, but … I don’t know, something about it doesnt make me happy. AngelScript has also been floated, but I don’t know what the point is of embedding a language in a C++ application that programs exactly like C++. Next week, we’ll explore more interesting and arcane alternatives. Like that Erlang thing.
Pingback: Technical Debt « Gaslamp Games