Skip to content

Understanding Behavior Selection

Mike Lewis edited this page Jul 10, 2018 · 1 revision

There are a few important elements to how Curvature chooses what behavior an agent will carry out:

  • The archetype assigned to the agent
  • The behavior sets available to that archetype
  • The behaviors contained in those sets
  • The considerations for each behavior
  • The contexts (targets) available for the behavior at a given moment in the simulation

The first four subjects should be adequately explained elsewhere, so this page will focus on the final element: how targeting works and why it is implemented the way it is in Curvature.

Behavior Selection

Choosing a behavior requires first knowing what our options are. To generate a list of possible behaviors, Curvature looks at the current agent and every other agent (or other target) that is available in the simulation. Each combination of behavior and possible target is recorded as a context. By necessity this is a polynomial growth in the number of contexts considered. The purpose of considerations is then to eliminate contexts as quickly (and cheaply) as possible.

Curvature omits one important optimization, which is short-circuiting. With this optimization, as soon as the score for a consideration reaches zero, the context is no longer evaluated and further considerations on it are skipped. This allows trivial rejection of inappropriate or impossible targets before any complex logic is evaluated on a target. Note that while this optimization is crucial for performance in real simulations, we have deliberately chosen not to use it in Curvature, so that the scores of all considerations are always visible. In our experience this data being available is much more important for education and experimentation, and Curvature is not designed to be performance-optimal to begin with.

Self-Targeting Contexts

Because of the nature of contexts, and to simplify the decision selection code, we have chosen that all behaviors must have a context, which is again a pair of a behavior and a target. If you have a behavior that does not need (or should not) target other agents, make it a self-targeted behavior instead. This is done by checking the "Can Target Self" option on a behavior. Typically this also means unchecking "Can Target Others". If a decision has neither option selected, it cannot be assigned to any context, and will be ignored at simulation time.

Why Evaluate Every Target?

Fundamentally this is essential to the design of utility-based AI architecture. The alternative is to pre-generate a list of targets using some simulation-specific code, and then select among them using utility scoring. However, this alternative is extremely flimsy in practice. Suppose we pre-generate a list of targets A, B, and C, according to some criteria. We then utility score them all, only to discover that all three targets are ineligible for selection (all behaviors against them score zero). The player then notices that our agent has opted to do nothing, since the agent has no viable targets, but the player can also see agent D standing right there who would have been a perfect target. This is an embarrassing failure mode, and it is surprisingly easy to get bit by it.

Clearly, the way to avoid this debacle is to merge the rules used for target selection into the rules used for target prioritization. The only time an agent will stop doing things is if there is literally no choice. (Note that this stall case can be detected even within the utility system itself and used to play a "confused" animation or bark.) Moreover, agents will still select desirable behaviors even if their immediate surroundings contain only undesirable options.