AiGameDev.com

“Join leading experts and industry veterans in Paris on June 23-24 for the largest independent conference about artifical intelligence in video games.” — Alex

membership

The Premium Membership area at AiGameDev.com is the best place to stay on the cutting edge of artificial intelligence in video games.
Find out more!

sponsors

categories


subscribe

Search


related articles

Sponsors

SpirOps

PathEngine


A Low-Level Task Class

Alex J. Champandard
May 31, 2007

From a design perspective, it’s useful to think about concepts like behaviors for actors. But on the programming side you’ll need something more concrete. What’s the simplest primitive you’ll need in the source code to implement all the behaviors you have in mind? Usually, it’s a piece of code that can run over multiple frames, i.e. latent execution.

Many dynamic programming languages have the concept of a coroutine which does exactly this. A coroutine is like function that can execute in its own context, but interrupt itself during execution and return control to its owner. In these modern programming languages, you can simply return control to the parent temporarily with one instruction, like yield or pause. Then the next time the owner runs the coroutine, it resumes where it left off — with all the execution context intact.

Game engines, however, are mostly written in C++ these days — which is neither dynamic nor very modern. And implementing full coroutines in this language is not a trivial affair. So what game developers usually end up doing is a compromise, implementing lightweight coroutines. I call these tasks. They have one function to call, and optionally, data associated with them.

class Task
{
public:
    virtual Status execute();
    virtual ~Task() = 0;
};

The owner of the task always calls the execute() function, and the task itself is responsible for deciding where it should pick up from last time. The status tells the parent if the task is still Running, of if it has Completed.

Your custom tasks that implement behaviors should derive from this class. (The destructor is abstract to force you to do this.) Once you have this in place, you can start thinking about managing tasks centrally, and worrying about what to do when they fail.


Bookmark and Share




Comments