The Importance of Actions and Conditions

Alex J. Champandard on July 30, 2007

Whether you’re building your AI as a behavior tree, a finite state machine, or a planner, it must be able to interact with the game. That’s what actions and conditions are for.

Because they are so fundamental, it’s important to get them right — even more so than other modular behaviors. So, back to basics…

Similarities and Differences

Conceptually, there aren’t many differences between conditions and actions, but the following is typically established as a convention:

  • Actions do stuff in the world, and they have side effects. Actions run for as long as necessary to achieve their purpose.

  • Conditions just check for information, and are free of side effects. Conditions may be used for one-shot checks, or monitoring a truth value.

Now for the similarities; actions and conditions both:

  1. Interact with the virtual environment in some way.

  2. Are written in the same language as the game engine.

  3. Should indicate whether they succeeded or failed.

  4. Can terminate instantly or execute over multiple frames.

It’s best to have actions and conditions as similar as possible, as it simplifies the AI framework. It also implies a single API can be used…

Common Interface

Many games have an interface which allows computation to be spread over multiple updates. This is ideal for implementing conditions and actions. It typically looks like this:

Initializes the action or condition by accessing the interface to other components in the game (e.g. audio, world representation), and/or setting up an internal data-structure (e.g. for animation control).
Uses the interfaces or data-structures setup by start() to perform the necessary computation (e.g. finding nearby entities) or supervising the execution of some functionality (e.g. playing an animation).
Shuts down the interface to other game components if necessary, and stops the external computation (e.g. request a sound to be faded out).

Actions and conditions typically do not need a life-cycle beyond their activation pattern. In contrast, higher-level behaviors may need persistent task memory, so additional init() and shutdown() can be used separately.

Words of Advice

1) Consider establishing three termination codes for succeeding, cleanly refusing to run, and failing with an error. This opens up many more options to the decision making system. (This particular tip is among the most important things I’ve learned recently.)

2) Get a sensory system to batch-up all of the hard processing so the conditions are lightweight. This applies for line of sight checks, capsule collisions, etc.

3) Similarly, decouple the actions from the simulation itself so everything can be updated at once. This applies to physics simulation and audio, for example.

4) Try to keep the interface as simple as possible. A complex API at such a low-level can cause many more problems than you anticipate. In particular, think wisely about the return values of the start() and update() functions, what they mean, and establish a contract to describe if/when these function are called based on the return values.

Do you have any particular conventions for your actions and conditions?

Discussion 3 Comments

leghan on July 31st, 2007

Hi, I have been recently thinking of an architecture for the AI actions. I agree with the importance of having well defined actions and conditions in the engine, so as to keep clear were que actual interaction with the world is done. In my vision, I add another method to actions: + CanExecute. + Execute (->Start) This makes possible to encapsulate the conditions within the action. Of course you should have the possibility to add additional conditional check in your behavior code. This way, I do encapsule the 'prerrequisites' of an actions as part of the action, and let the caller use additional conditions for its local purpose. Another point is that as long as actions can take time to execute, it can end by itseft, or be interrupted by the caller. So I add the following to the interface: + IsFinished + Finish + GetEndResult This let the caller pool the action for waiting till its completion, or instead force the ending of the action by calling Finish. And in any case, the result code is consulted using GetEndResult.

alexjc on August 3rd, 2007

Hi Angel, That's a very sensible and practical API which I've seen used before too. It's probably functionally equivalent anyway, so it's just a matter of preference! [B][TT]CanExecute()[/TT][/B] I like to have this condition integrated into the action itself, because in most cases you just end up doing this: [CODE] if (action->CanExecute()) { action->Execute(); } else { // Fallback. } [/CODE] Having a different return status for failing the condition check (FAIL), and having a problem during execution (ERROR), helps unify these two into one, so you can have a cleaner API... I also like to keep any other conditions separate and data-driven (i.e. the [TT]ShouldExecute[/TT]) so that the designers can easily create this with scripts... [B][TT]GetEndResult()[/TT][/B] I like to keep this out of the interface because each action tends to return different information. I use a visitor instead to get the data in a type-safe way, as it's only necessary a few cases. Alex

leghan on August 3rd, 2007

Hi, thanks for the comments. In my dessing, I have an ActionService, which facillitates the action user the call, so the 'If (Can) then Exe' is programed only in that action service, but the behaviors still have the possibility to check for the conditions of and action, without the need to execute it. Maybe it could be not useful in many projects, but for example may be useful if you want to separate the action requests, from the actions executions (for example if you want to make your AI execution multithreaded), as to performe them all in a specific code of your engine. This way, the behavior who is going to request an action, can check 'a priori' if that action will be acknowledge or no, an so maybe select a different action which is sure that can execute. Keep doing so well with your site :) Angel.

If you'd like to add a comment or question on this page, simply log-in to the site. You can create an account from the sign-up page if necessary... It takes less than a minute!