When the codebase of your game project becomes bigger and bigger, it can be a good choice to integrate a scripting library. There are several benefits in using a scripting language that way, for example, seperating the engine code and the story code properly. But it's also a way to lure casual programmers into your project, since it is easier to create mods without the need to recompile the binary and dealing with stuff like memory management.
You probably want a small, fast programming language to do the job, which does not hog all the memory for its standard library. But don't worry, no need to reinvent the wheel, you even have the choice!
The next chapters will deliver some concepts and ideas.
The basic idea
Imagine, you create an RPG with lots of items. Since it may be necessary to change the values to improve the balance from time to time, it would be very annoying if that would require the programmer to recompile the code. So one want to be able to change such values without recompiling, maybe even at runtime in a hidden in-game editor. To be able to do that, one must store these values as data files, be it some obscure binary format, *.ini files, XML, JSON.
But what, if one want to store the behavior of game entities?
The most simple answer to that problem is a primitive command based language like this:
PlayerStep forward 20 PlayerRotate 30 ...
To speed up execution of code like this, the text should be replaced with numbers at the loading phase:
1 1 20 2 30 ...
If you need conditional branches, you can implement a simple label/jump system, not unlike in assembly language:
LineElevenLabel: PlayerEatCake Check playerStillHungry : LineElevenLabel
The advantage of a system like this is obvious: It's rather fast to implement. For example, it can be parsed using regular expressions only. While it may be a good choice for many cases, for many other it isn't fine grained enough.
The rule of thumb is: If there is the chance that you ever will need something more complex than simple "if X do Y" branches, use a full interpreted language for scripting.
Be aware that implementing your own interpreter is a lot of work; in the most cases, you are better off using an existing library as presented near the end of this article.
Coroutines, also known as green threads or micro threads (although the terms don't mean exactly the same), are pieces of code that behave similar to a real thread, but instead of letting the OS do the scheduling, they let the process do the scheduling. This leads to a much reduced overhead and also to much more control over the threads. The reason why they are important in gaming is that they allow the creation of actor based scripting and cutscene scripting without falling back to state machine handling. Simple example (pseudo language):
def cutscene(): bob.walk_to(alice) bob.say("Hi") alice.say("Welcome, follow me") bob.follow(alice) alice.walk_to(exit)
What happens here is that Bob goes to Alice, talks a bit and then follows her. Unlike normal code, the running game is not interrupted, but instead the code just inserts tasks into the engine and then waits for their completion. This allows to program sequences. The implementation would look something like this:
class Actor: def walk_to(target): set_target(target) suspend()
The set_target() call, schedules the next tasks, while the suspend() call interrupts the script and returns control to the engine. Once the task is completed, the engine will resume the script and continue at the exact point where suspend() left. On the engine side things look something like this:
scripts = [Script("cutscene1.script"), Script("background-animation.script")] while(1): for script in scripts: script.run() process_input() update_world() draw()
There is a list with running scripts that gets called each frame. Each frame runs until it encounters suspend() and then gives control back to the engine. The whole stack of the script is preserved and allows the script to continue where it left of. Some script engine allow more tight control and for example give you the ability to limit how much CPU a script might take, so that a script gets automatically interrupted when its over its threshold.
(In fact, most of the scripting languages seem to support that feature.)
Languages suitable for game scripting: Small and embeddable.
- ChaiScript - C++ like syntax and max interoperability to C++
- Angelscript - C++ like syntax, uses a GC/RC hybrid and native C/C++ data types for better performance
- Game Monkey Script - with C like syntax, light and fast
- Lua - one of the most popular game script languages, pretty small, fast, with a clear syntax. You might want to take a look at LuaJIT
- Wren - "Think Smalltalk in a Lua-sized package."
- Squirrel - with C like syntax but more like lua with classes (e.g. supports Lua tables), GC/RC hybrid, used in Left 4 Dead 2 and Portal 2
- Croc - somewhat similar to Lua and Squirrel, but written and supported in the D programming language, successor of MiniD 2
- Falcon - you should consider it, if you need multithreading and good performance, also when interfacing the host system
- Tcl - everything is a string until proven otherwise, but if you need decent string support, it might be a good choice
- mruby – a small Ruby implementation suited for embedding
- NekoVM – a VM for embedding which is targeted by mature languages as Haxe.