February 7, 2011

A simple scripting system (as used by EGV)

Filed under: Technical — wickedworx dev clone 1 @ 6:40 pm


Excruciating Guitar Voyage was a game driven by content, as a lot of adventure games are. A key component in the arsenal of any content/story driven game developer is the ability to script game and world events.

A lot of developers, when talking about scripting, will think of LUA, JavaScript and AngelScript. But it is worth me saying – these may be “scripting languages”, but that doesn’t mean they are necessarily the right tool for the task of scripting events in your game.

For EGV, we wanted a scripting system which was higher level than what a pre-existing scripting language would provide.. a system which gave us direct control of the game. Another key element was that we wanted to be able to switch between a script ‘blocking’ the operation of the main game, and a script running alongside the main game per command… but I’ll get on to that later.


This example is all in C#. I have implemented this exact same system in C++ on previous occasions…so, uh, write it in whatever language you want – the concept is the same.

Our requirements for this system:

  • High level – to the point it is almost ‘game specific’, and that game specific commands can be added
  • Mixed blocking/passing (similar to ‘mixed asynchronous’) behaviour
  • Simple and quick to use, reasonable to debug
  • Fast to parse (we pre-cache all potential scripts on level load)
  • Not exclusively for cutscenes – player doesn’t have to stop playing while scripts are running
  • Conditions, and branching (“if” support) would be ideal*

OK – so a few assumptions of the game:

  • All important game objects have a “tag” name.
  • There is a “GameResource” which contains a reference to pretty much any game system we may need
  • Game Objects in EGV use a component system. This shifts behaviours in to separate components, making it ideal for this kind of scripting.

* Branching/conditionals to be covered in next post.. we’ve already got it implemented, but I’ve taken it out from this code to avoid too much early bloat in the tutorial. Next post will go about adding it back in!


Our scripting system consists of 3 main classes:

  • ScriptManager – holds a list of all currently running scripts, updates as necessary
  • Script – a script. holds a list of all the commands it must run, updates as necessary
  • IScriptItem – class off which script commands can inherit

class ScriptManager    
    GameResource m_gameResource;        
    List<Script> m_runningScripts = new List<Script>();        
    List<Script> m_toAdd = new List<Script>();

Notice I’ve got two lists: “Running Scripts” and “To Add”. The second list is there in case one of our scripts launches another scripts while running – it means we can get around modifying the “Running Scripts” list while it is being iterated through. Each frame, scripts from the “To Add” list are copied to the “Running Scripts” list, and the “To Add” list is subsequently cleared.

See ScriptManager here http://pastebin.com/hg3nBMR0

So, the idea is:

  1. Event happens in game, causes a script to be loaded
  2. ScriptManager creates a new script, using the data from the .xml file
  3. Script reads data from xml file and creates an IScriptItem for each command* within it
  4. The Script now contains a list of IScriptItems and has a “current index” variable which stores which script command it is currently running
  5. Next frame, ScriptManager calls update on the new script
  6. Script calls ‘run’ on the first IScriptItem in the list. If/when this command is finished, it moves on to the next command.


So, there are two different situations which we have to take in to account:

  • Situation A) We want to run a number of script commands all in one frame. e.g. we want to remove the banana object, add an explosion there, play an explosion sound, spawn some particles. This all has to be done in one frame – if this were spread out over four frames (e.g. one frame per command) – it would look ridiculous.
  • Situation B) We want one script command to keep running for a number of frames. e.g. we want to wait 2 seconds between blowing up the bin and a character commenting on the fact the banana has exploded.

This is the interface which I came up with to solve these two situations:

public virtual void run(float dt) {}        
public virtual bool shouldUpdateGame() { return false; }        
public virtual bool isComplete() { return true; }

Note, I decided against a “pure” interface and have opted to add ‘defaults’ to the functions “shouldUpdateGame” and “isComplete”, as the majority of script commands will end immediately and not need a game update.

So here’s the idea in bullet-point go-to logic:

  • point A) Game is updating. Game updates  full frame, then updates ScriptManager.
  • point B) Script Manager runs, updates script, RUN is called on the current ScriptItem (using our index!)
  • shouldUpdateGame() is called and the result stored
  • isComplete() is called. If this returns true then the current ScriptItem index is increased
  • if the result stored from shouldUpdateGame is ‘true’, we’re back to “point A”.. if it is false, don’t update the game – essentially carry on from “point B” without letting another frame pass — UNLESS this script has entirely finished, in which case, we’re done anyway!

Here’s the logic for that:

public bool run(float dt)     //   Script.run(float dt)
    bool shouldBreak = false;            
    while ( true )	        
        if ( m_itemIndex >= (int)m_items.Count )		        
            return false;	// return false - this script is finished	        
        if ( shouldBreak )		        
            return true;        // return true - let game carry on, but this script has more to do next frame
                               // Continue on - run the next item        
        shouldBreak = m_items[m_itemIndex].shouldUpdateGame();		        
        if ( m_items[m_itemIndex].isComplete() )		        


So, now we have the logic to run a linear script – we just need a few implementations of commands and a way to build a script!

The format of one of our scripts is as follows:

<command_name parameter1=”example parameteranother_parameter=”10” />

In our framework, across all our systems we have a unified XML load system. This converts XML (like above) to a tree of DataNodes. DataNodes have a name, an optional value and an optional list of child nodes.
In the above example, we’d end up with a DataNode with a name “script”, with a child DataNode (named “command_name”), with two child DataNodes (named “parameter1” and “another_parameter”), which have values of “example parameter” and “10” respectively.

Let’s add a couple more functions to our IScriptItem:

class IScriptItem    
    GameResource m_gameResource;        
    public virtual void run(float dt) {}        
    public virtual bool shouldUpdateGame() { return false; }        
    public virtual bool isComplete() { return true; }        
    protected GameResource getGameResource()        // protected, access to GameResource
        return m_gameResource;        
    public void baseSetup(GameResource gr)        // set up base (don't rely on ScriptItem implementations to remember this)
        m_gameResource = gr;        
    public virtual void setup(DataNode node)        // set up function for overriding - passed a DataNode

I decided to keep the name “IScriptItem” despite it not being a pure interface.

A Script is constructed from an xml file, which is converted to a DataNode. It then constructs all its script commands using the list of children in it’s DataNode. Each command in the script is build from a DataNode (and its children)

class Script    
    List<IScriptItem> m_items = new List<IScriptItem>();        
    GameResource m_gameResource;        
    int m_itemIndex;        
    String m_filename;        
    bool m_shouldDelete = false;

    public Script(String filename, GameResource resource)
        m_filename = filename;            
        m_gameResource = resource;            
        DataNode rootNode = DataNodeResource.getDataNode(@"Content\scripts\" + filename);            
        m_itemIndex = 0;            
    void addFromNode(DataNode node)        
        int nodeCount = node.getNodeCount();            
        for (int nodeIndex = 0; nodeIndex < nodeCount; ++nodeIndex)            
            DataNode thisNode = node.getNode(nodeIndex);                
            String itemType = thisNode.getName();

So, here we are iterating through command nodes, and getting a string from each – “itemType”. Using this itemType we can determine which class (inheriting from IScriptItem) to create an instance of. In our current code, we use Generics and a Registered Builder pattern to avoid a huge series of “if-else”.. but for this example, it’s probably easier to go down the “if-else” route! (There’s enough examples of using Generics to build objects from Strings in C# on the internet already!)

            IScriptItem itemToAdd = null;
            if ( itemType == "wait" ) // replace these else-ifs with your favourite String -> Object building logic
                itemToAdd = new ScriptItems.Wait();
            else if ( itemType == "play_cue" )
                itemToAdd = new ScriptItems.PlayCue();

            if (itemToAdd != null)
                itemToAdd.baseSetup(m_gameResource);   // set up base
                itemToAdd.setup(thisNode); // pass data to item set up
// throw an exception or do some error thing here - you've tried to use a command in your script which doesn't exist!

Full Script class here http://pastebin.com/DbX9SGUz

Command Logic

The great thing is – every time we want to add a new command, we just add a new class inheriting from
IScriptItem. EGV has about 30 commands, some of them very specific (“walk_to” and “speak”), and some of them more generic (“spawn_object”, “remove_object”, “set_animation”).
Adding new commands doesn’t seem to happen very often, and when it does – it’s usually a fairly quick addition…most of our commands involve finding a GameObject in the world, and calling a function on them.**

So, that should deal with adding two types of item – a “wait” and a “play_cue”. How do these look?



class Wait        :        
    float m_delay;        
    public override void setup(DataNode node)        
        // read in the delay required         
        m_delay = node.getNode("time").getValueF();        
    public override bool isComplete()        
        // this command isn't finished until the delay is over
        if (m_delay < 0)            
            return true;            
        return false;        
    public override bool shouldUpdateGame()        
        // we only want the *script* to wait, the rest of the game should carry on in the mean time
        return true;        
    public override void run(float dt)        
        m_delay -= dt;        

In Script

<wait time="5" />

This will cause a pause of 5 seconds in the script, while the game continues. Very useful in a script!

Play cue


class PlayCue        
String m_cue;        
    public override void setup(DataNode n)        
        m_cue = n.getNode("cue").getValue();        
    public override void run(float dt)        

In Script

<play_cue cue="fx_explode" />

End of side 1

Well, there you have it – a simple linear scripting system – great for cutscenes. It’s a 5 minute job to add a new IScriptItem – so if you want a command to kick off an animation, set the camera’s target position, tell a character to walk to a new location, wait for a character to finish walking to their target location.

The majority of ‘acting’ logic still must be in your game objects (e.g. your script may command your character to walk to “location X”, but it is the character’s update which is responsible for actually walking him there). Using our component system, we have a component “ai_walk” which is responsible for this behaviour. If you command an object to walk, which doesn’t contain an “ai_walk” component – it simply won’t go anywhere…

Here are a few example script commands we use:

  • Spawn Object
  • Remove Object
  • Walk To (character walking)
  • Add Focal Point (camera)
  • Remove Focal Point (camera)
  • Add Objective (for player’s objective list)
  • Remove Objective
  • Speak (character talking)
  • Wait for talk (wait for a character to stop talking)

So, even this small set of commands, it is possible to see how a cutscene with a couple of characters talking / walking to a new location can be easily created.. (and object being added or removed, the player’s objectives being updated etc..)

In the next blog on this subject, I’ll write about how we implemented branching (IFs, etc..), variables and conditions.. transform this linear system can be transformed in to a full script language that can be used for more than just cutscenes.

**While on the train today, I had some thoughts about how this system could be made more “OO”, and more cohesive with our existing GameComponent/Message system… so maybe I’ll write a post about that (and why I don’t think we’ll be switching to it immediately) some time!


February 1, 2011

post ‘world of love’ update

Filed under: Uncategorized — wickedworx dev clone 1 @ 12:41 pm

Friday was the World Of Love independent games development conference, in London. I went along not really knowing much about any of the individual speakers or companies involved…but I guess that was half the point, right?

There were some interesting talks (the highlight, for me at least, being a talk by the creator of “Dark Wind“, a one-man created mmo. very impressive, and stand-out. Some of the other talks were more along the lines of “this is our company, and this is how we work” – which, for me, is less interesting…especially when these companies tend to act more as an outsource for IP-owning clients, rather than really developing independent projects. – not really so much the side of things that I’m interested in, personally.. although there are some areas of cross-over, I’m sure.
All in all a very good day, met some genuinely enthusiastic indie devs (and non-devs) and had 3 cups of tea. Also had this cake which was really good.
So is there a place for content driven independent games? Uh.. well, I guess we’ve still got that to answer. And I guess the main thing that stuck with me from the day is: “How do you describe Excruciating Guitar Voyage (series) in one sentence?”. That’s something that’s got to be thought about.

(SIDENOTE: EGV1 is now popular enough that it has been pirated, by some pirate group. thanks a lot, you dicks!)

The next morning, we went along to the post-WoL game-jam (we being myself, Joakim and Ben)..we’d had about 2 hours sleep after a particularly tiring evening/night/morning in Islington, and it was showing.. we created a small game, which I’m currently calling “Tortune”.. it’s a spinning disc rhythm game with poly-rhythms and awkward sounds.. it was pretty much a manifestation of our exhaustion, in game form.. we made a 2 player mode which was way more fun, but then we added some animals textured with train seat textures – and you couldn’t see them that well with 2 players – so it was back to 1 player… It was great to hang out with some other devs and see some of their work… and, uh, apologies we were such a state!

Monday – back to EGV2. The “isolated puzzle area” I’ve been working on is all coming together well.. it’s actually gotten to be quite large.. hopefully not too large. It’s got ghosts, gingerbread, and bookcases.. it’s all a little spooky!
Got some awesome new assets from Tim. EGV2 is going to look great. A few people played a section of it over the weekend – which has led me to think it needs a little difficulty balancing… we hadn’t done any real testing (of any kind) with EGV2 previously, so it was nice to see a few reactions. The intro and new animations seemed to impress, so that’s GOOD NEWS.

Stick Unleashed went back in to peer review yesterday…. We got loads a bit of Kieronononon recording done – some of which will almost definitely end up as part of the EGV2 soundtrack. So, yeah, I’ve been busy.

well, that’s my blogbligation complete for this week. BYE. fucking screenshots next time, yeh?

(oh yeah, PX has new legs:

Blog at WordPress.com.