Coding Synergies: State Machines and Asynchronous Functions

Like chocolate and peanut butter, some combinations are greater than the mere sum of their parts.  Such is the case in game programming when two techniques can eliminate common problems when used in combination.  In this article, I’ll talk about why I’ve found states machines and asynchronous functions to be so useful when used together.

Most of the functions you call in game programming are synchronous, you call them and they return immediately with a response.  As long as nothing is screwed up, they run fast enough that they are, for all intents and purposes, instantaneous.

Of course, not all operations are so quick: reading data from a disc, accessing data from a remote server, etc.  These sorts of ops often take time that’s measurable in seconds, not milliseconds.  Naturally, we don’t want to completely freeze the game while such an operation is going on, so we turn to asynchronous functions.

With an asynchronous function, you call a function and then continue execution without waiting for it to finish.  Later, you either poll some other function to see whether or not your async function call has finished or you wait for a callback function to be called.

While you can certainly run all sorts of useful code while an async operation is running, you will inevitably have to wait for it to finish at some point before continuing execution.  Unfortunately, waiting is not a strong suit for procedural languages like C/C++.  Even while you’re waiting for an async function call to finish, you’ll want to do things to let the user know that your program hasn’t crashed.  Spinning icons and the like.

In essence, you want to time-slice execution alongside the other components of your program and allow your code to say things like: “Okay, is the async function done yet?  No?  Okay, then I’ll finish up here and let someone else do some work.  Call me in a frame so I can check again.”

This is where state machines come in.  They can make implementing that sort of waiting code trivially easy.  If you need to show a spinning disc icon while data is being loaded, just create a “Loading” state for your UI and, based on either a callback or polling an IsLoadingDone function, change to another state once loading is completed.

So, for example, if you had a state machine implementation that represented states as C++ classes and a file manager that could queue up files to load asynchronously, you might see code like this:

void LoadingState::BeginState()
{
  FileManager::QueueLoad("enemymodels.dat");
  FileManager::QueueLoad("background01.dat");
  FileManager::QueueLoad("enemyvoices.dat");
}

void LoadingState::OnTick(float deltaSeconds)
{
  if( !FileManager::IsLoadingFiles() )
  {
    GotoState( "LoadComplete" );
  }
}

void LoadComplete::BeginState()
{
  //Do Post-load stage initialization here
}

Or, for the more callback function inclined, you might have a situation like this when accessing network resources (like leaderboards):

void UpdateLeaderboards::BeginState()
{
  NetworkInterface->QueryLeaderboards( UpdateLeaderboards::OnQueryComplete );
}

void UpdateLeaderboards::OnQueryComplete(LeaderboardData* pData)
{
  ParseLeaderboardData( pData );
  GotoState( "LeaderboardUpdateComplete" );
}

Not too bad. It’s fairly simple code that most programmers and scripters can grasp immediately, which is exactly what you want when your project’s schedule is coming down to the wire.

So, my major takeaway is this: if you ever find yourself putting together a game where you will need to access resources asynchronously (I can’t think of any game projects where this wouldn’t be the case), you MUST make sure you have a decent state machine implementation in your engine to aid in using said asynchronous functionality.  To do otherwise would be downright cruel.

Share this Article:
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • Print