Behavior

This page describes the basic building block of AI Entity logic - the Behavior class. To define any action that an entity can perform, you have to create a corresponding class inheriting from Behavior. Entities can perform only one behavior at the same time.

Important methods

Start

This method is invoked once the Behavior is assigned to entity. Its implementation is not required.

Update

This method is invoked during each AI Manager update.

Its implementation is required.

Finish

This method is invoked once IsFinished method returns true, before the next behavior is chosen.

Its implementation is not required. Your implementation may behave differently depending on behavior status.

IsFinished

This method returns true if the behavior should terminate.

Its implementation is not required. The default implementation returns true.

IsLegal

This method indicates whether it’s possible to execute the behavior and if it should be considered by decision making algorithms. If a behavior turns illegal during its execution, it will be automatically finished with DELEGALIZED status.

Its implementation is not required. The default implementation returns true.

IsInterruptible

This method indicates whether it’s possible to interrupt behavior execution. If it is Reasoner may decide to finish behavior immediately with SUSPENDED status.

Its implementation is not required. The default implementation returns true.

Behavior Status

Behavior may be in one of following states:
  • ACTIVE - behavior is currently assigned to entity

  • SUSPENDED - behavior was assigned to entity but its execution was interrupted

  • FINISHED - behavior finished properly

  • DELEGALIZED - behavior is no longer legal

Simple behavior implementation

An exemplar implementation of a simple behavior looks like this:

  • C++

  • C#

class GoTo : public grail::Behavior
{
private:
  Location target;
  Unit* controlledUnit;

public:
  GoTo(const Location& target)
    : target{target}
  {
  }

  void Start(AIControlledEntity& owner) override
  {
    controlledUnit = owner.GetBlackboard().GetValue<Unit*>("controlled_unit");
    if (controlledUnit->GetCurrentLocation() != target)
    {
      controlledUnit->GetMovement().GoTo(target);
    }
  }

  void Update(AIControlledEntity& owner, float deltaTime) override
  {
    //Place any time-dependent or durable logic in behavior's update
  }

  void Finish(AIControlledEntity& owner, BehaviorStatus status) override
  {
    controlledUnit->ReportMovementFinished();
    //We may also place any cleanup logic in this method
  }

  bool IsFinished(const AIControlledEntity& owner) const override
  {
    return controlledUnit->Location == target;
  }

  bool IsLegal(const AIControlledEntity& owner) const override
  {
    //if IsLegal returns false, the behavior will be omitted by decision-making algorithms or interrupted
    return true;
  }
}
public class GoTo : Grail.Behavior
{
  private Location target;
  private Unit controlledUnit;

  public GoTo(Location target)
  {
    this.target = target;
  }

  public override void Start(AIControlledEntity owner)
  {
    controlledUnit = owner.Blackboard.GetValue<Unit>("controlled_unit");
    if (controlledUnit.CurrentLocation != target)
    {
      currentUnit.Movement.GoTo(target);
    }
  }

  public override void Update(AIControlledEntity owner, float deltaTime)
  {
    //Place any time-dependent or durable logic in behavior's update
  }

  public override void Finish(AIControlledEntity owner)
  {
    controlledUnit.ReportMovementFinished();
    //We may also place any cleanup logic in this method
  }

  public override bool IsFinished(AIControlledEntity owner)
  {
    return controlledUnit.Location == target;
  }

  public override bool IsLegal(AIControlledEntity owner)
  {
    //if IsLegal returns false, the behavior will be omitted by decision-making algorithms
    return true;
  }
}

API Reference