Scripting Languages

Posted by Astryl on Sept. 5, 2014, 6:28 a.m.

I decided last night to start writing a few more progress blogs for my more 'mundane' projects.

So here's a blog. It's probably dry, but you can always drink a can of soda while reading it :P

My Engine

Last month marked the 2 year anniversary of Exile, if you can call it that.

That also means it's been a whole 2 years I've spent working on the engine, making it the longest running project I've ever stuck to.

Recently, I started another engine for 2D games that had a few nifty features… but I decided that having two engines wasn't good for progress, so I pulled the new features from the new engine and replaced some of the old modules in Exile Engine (The Logger, Config handler, Object handler and Asset Loader).

I'll probably write a separate blog entry or two about some of these features, and how I implemented them… but today I'm writing about my choice of scripting language.

Lua

Exile was coded from scratch in C++. The original code was around 14000 lines of code, and was a tangled mixture of framework and game logic.

One of my major goals over time has been to separate the "Game" from the "Engine" in a comfortable way.

Recently, I added in Lua support to the engine, binding a lot of commonly used functionality, and managed to dynamically detect and load scripted objects at runtime (So new scripted entities could be created on the fly).

But I started running into a few major problems.

Firstly, I assigned each script a separate VM. For obvious reasons, this made communications between objects a nightmare.

I changed this to a single VM multi script system, where all scripts were loaded on startup, and a convention-based entry point was called.

Then I ran into my second problem. Lua is messy. That is, it gets messy when you start to code anything as complex as a game.

The syntax requires a lot of keywords I feel are unnecessary (do, then, end, for instance, could be replaced by { and }, and the language would feel a lot cleaner).

And the final problem was the way the engine used scripted entities. The ScriptedEntity type, a child of GameEntity, loads a script and calls the entry point (Based on the filename. So GameOverScreen.lua would have an entry point of GameOverScreenMain).

For various reasons, this ended up being a pretty much big mess. The entire engine is class based, but Lua doesn't have a good class system (Tables are messy when you try to make them 'work' in lieu of a good class type).

So to cut a long story short, I ditched Lua.

Alternatives

There were a few alternatives I was aware of, those being Python, AngelScript and JavaScript.

Through a process of trying things out, I discarded all three.

Python is too bloated, and binding classes is a pain in the ass.

AngelScript is too unstable, and has slowdown issues.

JavaScript is just one big 'no' for me, mostly because of the syntax. I know it's C-like, but some of the quirks put me off.

So I went and fished around a bit more, and found out about Squirrel, a scripting language that Valve has been using recently (Most notable in L4D2 and Portal 2, for scripted scenes apparently).

While the language itself is excellent, the Wiki isn't. Looks like there are no access permissions on the page, so it's full of spam ads, screwed up links and random text.

Not that you need the Wiki anyway. The library comes with a full manual for both the main library and the standard library extensions.

And it is beautiful.

Essentially, Squirrel is similar to Lua on its lowest level. Tables are the de-facto data type, but there exist mechanisms to define classes easily.

Instead of keyword based blocks, the familiar { and } are used instead.

And best of all, it's tiny. The source for the library is under 300KB of code, and is easy to compile.

And finally, it's fast. LuaJIT can beat it in terms of raw speed, but I'll take the better syntax over a few micro-seconds of speed gained :P

Persistent Problems

I got Squirrel integrated to my engine pretty quickly. I found a decent binding library called Sqrat that allowed me to quickly bind engine classes as actual class types, and static functions to the VM, and generally speaking… all was well.

Until I started trying to get things to work together.

Squirrel lacks script-side import/include functionality. Generally, one could just load all scripts in a directory on load and their contents would be added to the scope.

But I want things a bit clearer, and better defined.

For instance, one of the things I want to do is have certain engine modules call specific 'game' modules. At the moment my main modules are:

> Main Menu

> Editor

> Game

So ideally, there would be a separate entry script for each, with a convention-based entry point (S_main in my engine).

Squirrel has a 'dofile()' function that basically loads and evaluates a script file during runtime, from within a script… but I couldn't get it to work.

This might have something to do with the fact that I'm pre-compiling all scripts before running the game.

Sqrat also has an 'import' library that only seems to work on scripts that haven't been compiled yet.

And I kinda want my scripts to be compiled. I don't want people randomly screwing around with some of my core game logic :P

The solution

I spent most of last night thinking "Maybe I should write a tool that lumps all the scripts together when building and compiles that".

Then at some point while considering that, I remembered that I already had a tool available to do that for me: The C Pre-processor.

In my makefiles for the scripts, I invoke GCC with the -E and -x c switches, and output an intermediate script file that I then compile into the final module.

And all I need to do in my scripts is use the familiar #include directive.

Well, I'm done. Sorry if the blog rambles on a bit too much :P

Comments