AI tutorial: How to create an AI melee behavior using Flowgraph
Here I will explain how to create an AI behavior through the use of Flowgraph nodes. This is a melee AI, meaning it is designed for close-combat (sword-fighting, etc…).
The behavior itself is quite simple: the entity will approach the player and attack him. Sounds simple enough, but it will take into account a lot of little parameters like distance to the player (allowing multiple attack types depending on this distance), making sure the entity always faces the player before attacking, dealing different amounts of damage and physical impact depending on the attacks, etc…
In order to make this behavior available to any entity in the level, we will create Flowgraph modules. These will be the building blocks of our AI behavior. Note that they do not include any specifically named entity, since the goal is to make them generic enough so they work with any entity we choose.
To create modules, please refer to the official documentation page here.
Walk to the player:
The first module is called “walkToPlayer”. As the name indicates we will use it to tell the entity to go to the player (before it can attack).
When the module is called, we feed it the EntityId of the AI, so that the module knows which entity we’re talking about. We use a AI:GoTo node to direct the entity to the player’s position. We precise that the entity will stop at 2 meters from the player (which is the range of its sword attack).
However, sometimes things can get out of whack and the entity will attempt to keep on walking, even when standing right next to the player. In order to counter that glitch, all we need is a “walk break” timer. Every half-a-second, while the entity is walking, it will check the distance between the entity and the player (through a Entity:EntitiesInRange node). If the entity is within a certain threshold (in this case 1.9 meter), then it will cancel the walk action and thus end this module so we can move on to the next step.
Check the player’s position:
Now that our entity has just stopped walking, we’re going to check that the player is standing within a certain zone (notice I don’t use the term “area” to avoid possible confusion with the “area” entities) in front of it.
We will use the “playerInBox” module (cf. next chapter) to get the relevant info. At the end of the module we’ll know if the player is inside the zone we defined or not. That way the AI can decide to either attack (if the player is in the zone) or walk again (if the player somehow has moved out of the way).
Check if the player is in a specific zone:
This is the core of the player position checking process. What this module does is to get the location of a point that is always at a certain distance in front of the entity (or in the back, if the number is negative). It then uses this point as the center of a virtual spherical zone (of a radius defined by ZoneRadius) and checks if the player intersects this zone. If he does, then the module returns a “true” status. Status is “false” otherwise.
Attack the player:
Now it is time to attack the player. Again, this module is very specific to my AI character (a swordsman with a shield). When the module starts, we know the player is in front of the entity, within a certain zone radius (a fact we established in the “playerInBox” module).
So we start by checking the distance between the entity and the player. Not to find out if the player is within range (we already know that), but because if the player is really close to the entity then the entity will deliver a blow with its shield, to repel the player. But if the player is not too close, then the entity can deliver a sword strike. For variety’s sake I have two sword strike animations that are randomly chosen.
Once the attack is in progress, at a certain time -when the shield or the sword should make contact- we check if the player is in a very specific zone (a smaller radius this time) and depending on that result, we actually inflict damage to the player or not.
Note that the shield blow attack and the sword attacks each deal a different amount of damage and impact (the impulse node). They also each have slightly different criteria in terms of zone checking radius.
Create the behavior itself:
Finally we need to setup a behavior that will make use of all the modules we created. So this is an example of the simple behavior I mentioned at the beginning of this tutorial. Notice that this graph is reusable for any entity in the level. You just need to duplicate it and change the Entity:EntityId node to the left to point it to a specific entity in your level.
This is a very simple example, so as soon as the game starts, the entity starts to walk to the player in order to attack him. First I made sure that the entity draws its weapon and focuses its attention on the player (for the lookIk to work).
Note: This implementation not only completely bypasses any LUA scripted AI behavior, but also completely disregards the weapon’s damage defined in the weapon’s XML file.
Thank you to all the crydev community members who helped me devise this setup, especially Cry-Spiffy and The_Grim, without whom I wouldn’t have come this far…