Scripting
From FreeGameDevWiki
Contents |
Introduction
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 non-programmers into your project, since it is easier to create mods without learning a load of classes and doing all the nasty memory management manually.
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.
Coroutines
Coroutines, also known as green threads or micro threads, 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.
External ressources
Linux Solution Guide -> Microthreads (german)
A paper about microthreads in Lua
(In fact, most of the scripting languages seem to support that feature.)
Scripts with callbacks
TODO
Game State Saving
One issue that arises with scripting is that they are often hard to serialize. Proper solution for this is unknown.
TODO
Scripting languages
Languages suitable for game scripting: embeddable, yet performing well.
- 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
- 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
- Croc - somewhat similar to Lua and Squirrel, but written and supported in the D programming language, successor of MiniD 2
