AI Goals

May 16, 2012 at 9:20 PM
Edited May 17, 2012 at 8:59 AM

In the sample code, you add one goal at a time, both goals return 1 from EvaluateDesirablity and in ShouldStatusChange each goal has custom logic to compute if it should stay active anymore. On Wander complete starts Attack goal and Attack complete starts Wander goal. So its looks more of a StateMachine approach. Moreover you do override OnUpdate method of GoalBrain to write some custom code there. You do not override Process method of each goal. I see that more than one goals can be in active state, and EvaluateDesirability is called on all goals to constantly poll for most desirable goal but ShouldStateChange is only called on the most desirable goal.

Q1. what are the methods/places I should put custom logic in considering I have more than two goals and the transition between goals is not exclusive like state machines e.g. AttackPlayerGoal and EvadePlayerBulletGoal may be active at the same time but AttackPlayerGoal and WanderAroundGoal are mutually exclusive.

Q2. Should EvaluateDesirablity always return a constant float (hard coded) - or is that a candidate for custom logic that may return different desirability values at different times.

Q3. In your case one goal is terminated and another is started and you manage that by setting goal status to complete. In my case will it be correct to add custom logic to GoalBrain's OnUpdate method that decides if a Goal needs to be re-created? or should I just not set completion on goals to make them stay alive?

Q4. Should there be a need to overirde Goal's Process method to run custom logic? or should custom logic only be in "ShouldStatusChange" ( and "EvaluateDesirability")

I know I can skin the cat in several ways for my scenario but I dont want to "misuse" the framework, so need to know the right way :)

May 18, 2012 at 10:29 PM


You are right in the fact that I could have made the Ace on Steroids Goal make use of the integrated Finite State Machine system instead but I wanted to promote this one as it is mainly seen as the most powerful (and therefore potentially more complex to get right ;) )

Now, you should never override the Process method unless you want to override the way Goals are processed.

You must first understand that Goals are by nature atomic finite states and have 4 states: Inactive, Active, Completed and Failed.
When a goal gets activated you can implement state changes to your game entities such as activating a steering behavior like in Ace on Steroids or activating a custom Component that gets his Update method called every frame.
When a goal gets completed or failed, you should set a new goal either above in the Goals hierarchy or at the same level.
Finally, when a goal gets terminated, this is where you should deactivate a game entity state such as the ones mentionned when activated to get to its original state.

Q1. The best place to put custom logic (if you want to follow the IGF approach) would be to create custom Behaviors that are added to either a NonPlayerAgent or PlayerAgent associated to your game entities. This would let you make use of the Network independent logic system.
However, you may not want to rely on this, and you could simply create your own custom Components that you'd add to your game entities and activate/deactivate them whenever a Goal is activated/terminated.

Q2. EvaluateDesirability lets you return whatever float value you want. No need to be constant, if you have reasons to make custom decisions depending on context, that's the place where you should place such code. For instance, if you have a FindTargetGoal and a FleeGoal, you could for each of them have an EvaluateDesirability that would depend on the number of enemies close to the entity.

Q3. You should always consider creating/switching to another goal from goals themselves.

Q4. I believe I answered this point in the above responses.

Let me know if you need more info ;)