State Machines and Reacting

A bot will react differently for each situation. Depending on what is happening in the environment and whether the player can be seen or heard, a bot could be doing a multitude of things, such as resting, patrolling, attacking, dodging, chasing, running away, powering up, hiding, or whatever else you can think of. In previous chapters, you've already taken advantage of state machines, in which an object can have different states that cause it to perform different actions. For example, the base game object class had the idle, active, and destroyed states. State machines are also called finite state machines because there are a limited number of possible states. A finite state machine also defines how and when the object's state can change. For example, a bot can go from stopped to walking to running, but it can't go directly from stopped to running. Also, a bot might start walking only if the player is visible. Additionally, you can create a hierarchy of states. For example, the bots in this chapter will have three states that are considered "battle" states: dodging, attacking, and running away. Furthermore, the attack state could have different kinds of attack patterns. So, the hierarchy is battle as a parent, with three children and possibly a few grandchildren. Check out Screenshot for a visual look at the state machine you'll use for the AI bots in this chapter. This state machine has two basic parent states: battle and normal. A bot goes into a battle state only if the player is visible, and it returns to the normal state when the player is no longer seen.

Screenshot A bot state machine.

Java graphics 13fig04.gif

But just because the states show a hierarchy in theory doesn't mean you have to create any elaborate state code. Here you use plain old integers like you did for the previous state machines:

public static final int NORMAL_STATE_IDLE = 0;
public static final int NORMAL_STATE_PATROL = 1;
public static final int NORMAL_STATE_CHASE = 2;
public static final int BATTLE_STATE_ATTACK = 3;
public static final int BATTLE_STATE_DODGE = 4;
public static final int BATTLE_STATE_RUN_AWAY = 5;

You'll treat the AI state separately from the game object state so they won't interfere with each other. You'll actually use a few more states than this, but this a good starting point. Setting the correct AI state is straightforward, shown here in Listing 13.5.

Listing 13.5 State Machine Methods of AIBot
private int aiState;
private long elapsedTimeInState;
 Sets the AI state for this bot (different from the
 GameObject state).
protected void setAiState(int aiState, GameObject player) {
 if (this.aiState != aiState) {
 this.aiState = aiState;
 elapsedTimeInState = 0;
 // later, set the appropriate path for this state here.
public void update(GameObject player, long elapsedTime) {

Besides setting the state, you're keeping track of how long you've been in that particular state. This can be used if, say, you want to stop chasing if you've been chasing for too long. The setAiState() isn't complete: You also need to set the bot's path (using the PathFinder interface for the previous chapter) so that it follows the appropriate attack path, chase path, or whatever other path you are going to use. You'll add this a little later.