When developing my games, I find it convenient to perceive a game much like an operating system. Both have many things in common - they both have a centralized kernel (or core), they have strict performance requirements which must be met in real-time, they must manage myriad resources, and they both have a series of loosely coupled processes to perform various tasks.

In operating systems, process management has been very thoroughly researched. Resource allocation, scheduling, concurrency, intercommunication - all of these things have been studied to for years.

In video game development, at least on the hobbyist level, state management is an open problem. If you talk to ten different people about how to manage the state of a game, you will get ten different management strategies. And I’ve never been presented with one I liked. Until I looked at operating systems.

I now prefer to handle my game state flow with a process tree. That is, I have a series of processes that each have some small, indivisible task to perform. Each process can have any number of children and each one has its own resources. A process has full control over its children - it can add, kill, or manipulate them at leisure, but a process can not manipulate its ancestors or siblings. Most importantly, each process can receive and handle system events however necessary.

Part of what differentiates this system from an operating system process is that these processes can only respond to events - they are not always running concurrently in the background. In this respect, they moreso resemble interrupt handlers. I prefer to think of them as processes though, since they can have children and they have a large influence over the state of the system. Also, my processes are unprioritized; in operating systems you can assign a process a priority to determine how often it executes and you can also give processes fixed time limits before they must give up control. This may very well be something you want to consider for your own system, but in my system each process is guaranteed to receive every event it is interested in and can perform its operation in full before giving up control.

Intercommunication between game processes is done through typical event passing. Since processes are guaranteed to finish executing without interruption, we do not have to worry about race conditions. However, I could easily envision an advancement for multicore architectures where processes could run with true concurrency - increasing performance, but potentially complicating the system.

Here’s some commented psuedo-code for an abstract class Process which all other processes inherit from.

[ftf def="js.xml"]
abstract class Process inherits GameEventSubscriber
{
//Keep a list of all this Process’s children
private List mChildren;

//Determines whether the Process is alive or not
private bool mIsAlive;

//Called automatically when the Process starts. This
//is where initialization for the Process should begin.
//This is in contrast to putting the initialization in
//the constructor, since we want to wait until the Process
//is actually running before starting up some of its
//functionality.
//All Processes should call the base Process’s Start
//to provide some necessary functionality.
public virtual void Start()
{
mIsAlive = true;
post event (process started)
}

//Called automatically when the Process stops.
//This allows you to free up resources or perform
//certain functionality immediately when the Process
//stops running as opposed to waiting until the
//Process is destroyed.
//This method does not stop all of the children
//of this Process, which may be a possible
//improvement.
//All Process’s should call the base’s Stop to
//provide some necessary functionality.
public virtual void Stop()
{
mIsAlive = false;
post event (process stopped)
}

//Handles events sent to the Process.
public abstract void OnEvent(GameEvent e);
//Marks the Process as dead. This is how a Process
//signifies that it’s finished with its functionality and can
//be stopped. However, it won’t be stopped immediately.
//Would stopping it immediately be better?
//I’m not sure. ^_^
public void Kill()
{
mIsAlive = false;
}

//Returns whether the Process has been marked
//as dead or not.
public bool IsAlive()
{
return mIsAlive;
}

//Adds a child of this Process, automatically calling
//the child’s Start method.
public void AddChild(Process child)
{
mChildren.Add(child);
child.Start();
}

//Removes all the children of this Process,
//stopping them appropriately. Any children
//of the removed children will also be stopped at this
//point.
public void RemoveAllChildren()
{
for each child in mChildren
child.RemoveAllChildren();
child.Stop();
mChildren.Remove(child);
}

//Removes all the dead children of this Process.
//This function will search through all children,
//grandchildren, etc, looking for dead Processes
//to remove. Thus, it is only necessary to call
//this method for the top-level Process for
//all the dead Processes to be removed properly.
//When a Process is removed in this manner,
//all of its children will be stopped appropriately.
//Ideally, this should be called at least once per
//frame to ensure that Processes do not linger
//around.
public void RemoveDeadChildren()
{
for each child in mChildren
if (not child.IsAlive())
child.RemoveAllChildren();
child.Stop();
mChildren.Remove(child);
else
child.RemoveDeadChildren();
}
}
[/ftf]

There - that’s everything. Obviously there are improvements that could be made – you could provide facilities for suspending/resuming processes, for instance. It resembles C# to some extent, but I assure you that the code won’t compile as it stands. I won’t claim that it’s bullet-proof or even the most ideal implementation, but it’s been treating me pretty well.

Now to create a Process which actually does something, we inherit from this base Process and override the necessary methods. So here’s an example of a Process I’ve written which simply waits until a certain amount of time has passed.

[ftf def="js.xml"]
class ProcessWait inherits from Process
{
private long mTime;
private long mTimeStart;

ProcessWait(long time)
{
mTime = time;
}

public override void Start()
{
base.Start();

//Get the time this Process started.
mTimeStart = GetTickCount();

//Tell the global GameEventService that this process
//will listen for game events of type GameEventFrame,
//which is an event that is fired each frame. Obviously,
//how you do this depends on your event-passing scheme.
GameEventService.Subscribe(this, GameEventFrame);
}

public override void Stop()
{
//Unregister this Process so that it no longer receives
//events while it is stopped.
GameEventService.Unsubscribe(this, GameEventFrame);
}

public override void OnEvent(GameEvent e)
{
//Each frame, do something
if (e is GameEventFrame)
{
//Check if mTime amount of time has passed since the
//Process started, and if so, the Process is finished. Thus,
//we go ahead and Kill it.
if (GetTickCount() - mTimeStart >= mTime)
{
Kill();
}
}
}
}
[/ftf]

Simple, yea? You can make a bunch of little Processes just like that one which perform small pieces of functionality, and then those pieces can be combined to form bigger Processes that perform much larger tasks until, eventually, you can run the entire game through a series of well put-together Processes.