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
67 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:

Contents
 Script Anatomy
 Making IInstruction
 do stuff

 The Script Editor

 Printable version
 Discuss this article
 in the forums


The Script Editor

In "Fast Scripting" the script editor is very important! There are 2 ways you can do this: Write the scripts in a text file and write a script compiler, or combine them. I have a point-n-click editor. It's not the easiest thing to do, but it's very easy for the user to write scripts, and when I get all my code bug-free (there's still 1 obscure bug), it'll be impossible to have syntax errors, unless you try binary hacking (and since my scripts are compressed, hex editing the code will render the script unloadable).

I'll not cover having a seperate compiler. This scripting format doesn't lend itself to such editors in the hands of "novices". An all-in-1 editor works very well. Here is an old screen dump of my script editor. Never mind the Audio Player - Audio's important for games, but this is about scripts! :-P Seriously, this is how simple the user interface can be. And it's even more powerful than some of my competitors "compiling" editors. Those 2 arrow buttons on the side move the currently selected instruction up or down in the script. The main area is a standard list box control. In VB, it's increadibly easy to make. It's also a custom control, so if I wanted, I could make a window capable of editing 10 scripts simultaneously. Of all things, the up and down buttons are the hardest to do, and it's with those I have my bug.

Script Execution / Multitasking

I've covered loading in some depth. Saving is just the opposite to loading. Running is even easier still. Each Instruction implements a Run method, because it's part of the IInstruction interface. Therefore, it's the responsibility of each instruction to execite itself. The Run() method in CScript just starts the execution of FirstInstruction.Run(), and also just keeps the script executing in sequence.

Normally, this is fine, but occasionally you will need to have a script running all the time - kinda like having a thread. VB can't multi-thread as such, so we VB'ers have to improvise. Even so, with multithreading, you need to be careful to keep it all in sync with the game engine. So, in my scripting language, I have implemented "foreground" scripts and "background" scripts. The only difference is a boolean variable being set, and they're handled slightly different in the game engine. A CScript can switch between these 2 states with a CSetForeground and a CSetBackground instruction.

I have allowed for a collection class called CBackgroundScripts, which holds CScripts. Basically, there's a section in the game engine that handles running of scripts. For a foreground script, they're just individual scripts being run in turn. For background scripts, you cycle through the elements in the collection and call the run method.

For a normal script, it starts at the start, and ends at the end. But for a backgrounding script, this doesn't always have to be the case, and in some cases, it would be impractical to script this way. Also, a typical situation would be to have a script looping in the background, providing advanced graphical / gameplay services (this is one possible way a user can extend your game engine to suit them a little better). But, we all know, a CPU can only process one thing at once, so if you send a script into a long loop required for those services, then your game engine is going to lock up. This is where you could use multi-threading in C++ or Java. Another good way to skirt this problem is to have an instruction called CDoOtherEvents - you guessed it VB'ers, a Doevents equavalent in your language. For all those who don't know what Doevents is, it's a command that pauses execution at that place and allows for the system to attend to other things, like the User Interface, etc. This is ideal in our scripting language - if we can get the CScript to pause at that instruction, and finish execution temporarily, and then use the Run method in CScript to pick it up again, then we're there. If you add a member in CScript called CurrentInstruction (type IInstruction) and set it to reference the CDoOtherEvents before jumping out of the script's execution cycle, and then resuming execution of the CurrentInstruction.NextInstruction, then you're set. I'll let you work out all the little technicalities, but that's the easiest and most effective way I imagine it to be.

Be careful though - although I havn't tested this, if you process all the backgrounded scripts every cycle of the game engine, you are liable to drop your FPS. This can be addressed by executing them every 5 cycles or so.

Conclusion

Well, that's the framework I suggest for a nice, flexible, and fast scripting system. It hasn't failed me sofar, and even my more primitave version (not object orientated in the slightest) worked ok - just looping was out of the question without impolementing a Goto instruction, which is, as we all know, evil :-)

Feel free to use this model in anything you write, and to adapt it to your needs. If you come up with a killer concept that really enhances the model, drop me a line: airzone@rpgmaker.net