Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
100 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

Unlike better graphics, scripting isn't one of those features that you focus on in your game engine, but it is an important component. These days, game engines are required to be extremely flexible which makes them equally complex. In order to meet these goals, it's crucial to have a data driven design focus where the engine behavior is controlled by external data.

In a basic implementation, simple data structures such as Health, Speed, Object Placement and other game values are read from data files. We often need to do more than just specify the different colors of the enemies in a game, so this only meets half of our requirements. The fixed data format constrains what options are ultimately possible and it simply does not provided enough flexibility. We must also drive the game's logic and rules.

This is accomplished using some form of scripting language. This article explains how you can easily create a simple scripting language for your game and provides some sample code that you can quickly integrate in to your own game engine.

Traditionally games developed in-house scripting languages such as QuakeC, UnrealScript or similar resulting in a plethora of obscure game specific languages. Most people do not want to spend the resources to develop their own robust scripting language. A common option is to leverage existing languages like LUA, Python, Ruby or Java. Even when not, we are re-creating the wheel, using another embedded language isn't a perfect solution. It's still a hell of a lot of work to get them functioning and at the end of the day, there's a huge time investment to properly embed another language in to your game engine. And we all want to avoid as much of this work stuff as we can.

3rd party languages generally work great, especially some of the better supported ones but they do have their drawbacks.

  • Performance (Unless compiled to native code, but usually has limitations)
  • Interface between C/C++ and script can be constraining
  • Interface can be high overhead and maintenance even with automated tools
  • Usually lacks of good debugging and development tools
  • If interpreted there is no error checking until script is actually run
  • Learning and supporting an entirely new language requires a lot of extra effort
  • Lack of easily available libraries, extensions and documentation

Instead of embedding in other external scripting languages, it would be useful if we could use one we are already familiar with. C makes a wonderful base for representing a custom scripting language for your game. C will probably do every thing needed and you will be leveraging the power of a language with which you are already comfortable. It is much easier to distill down to elements that you need than to add a lot of additional functionality to something that does not do what you require.

There are some obvious benefits

  • A rich feature set with plenty of documentation
  • A wealth of existing tools to leverage
  • Fast, efficient, compiled, code
  • Extremely easy to interface with engine code

One of the biggest advantages is time and performance. It takes very little effort and time to learn and use. Chances are you are already coding in C/C++ and because it is all compiled code; the performance will be on par with whatever else you have written for your core engine. Using C is not without pitfalls either, the scripts can be very dangerous, and it would be difficult to create safe scripts that run in a sandbox. All this wonderful power means we could really hurt ourselves with a few bad scripts.

We cannot just use C as a script language without first jumping through a few hoops. It does have a serious limitation that we will illustrate with the following scenario. Let us say that a C function represents each script. The pseudo-code to call our C functions looks like the following.

main()
{
  script1(); // Call Script 1
  script2(); // Call Script 2
  script3(); // Call Script 3
}

In C we are only able to run these scripts sequentially from start to finish. This does not do us any good. Since almost all of our scripts need to run over time during the course of the game. The following is a pseudo-code example of a script that describes an explosion effect.

Script_Explosion()
{
   Create A Smoke Particle System
   Create Explosion Sprite
   Wait 1 Second
   Create 2nd Explosion Sprite
   Move 2nd Explosion Sprite Up 100 Units Over 3 Seconds
   Wait 3 Seconds
   Destroy Explosion Sprites
   Destroy Smoke Particles
}

In order to run this script, we will need to run the script for a fixed time, draw a frame, run the script some more, and draw another frame etc. until our script terminates.

The simple solution would to create a separate thread for each script. However, threads are not practical due to their operational overhead and performance constraints. What we want is something that behaves like a thread but is more lightweight so it can support a large number of scripts.

This brings us right back to the original topic of co-routines. Think of them it as a simple co-operative multi-tasking mechanism. They are very much like a thread except they run in a pseudo-parallel manner. Each co-routine represents a path of execution: they are able to stop after a certain time, and later continue where they left off. Unlike threads each script only runs by manually receiving control of the CPU, they must then manually give up control of the CPU at specific points.

This suits us just fine, since we do not want them to run all the time and interfere with the rest of the finely tuned code in our game. Just as long as each co-routine gets their CPU time between a render-frame, we are good. Each C script represents a function and runs as a separate co-routine.





Page 2

Contents
  Page 1
  Page 2

  Source code
  Printable version
  Discuss this article