This article is intended to explain the thought process behind Umbrellads' IAs, a Combat/Platformer 3d Game.
We started the project in October 2019. This article takes into account the current state of the game's IAs.
IA codesigned by Guilhem d'Humières and myself (Lucas Ferrantelli), with feedback from the rest of our team, especially Leo Marambat Patinote, who was in charge of programming the system described below.
Designing an artificial intelligence system is not easy, indeed, the first iteration is very time consuming, and may impact the production during the whole project. We had to find a modular system able to adapt to the future robots we may create, but also be easily modifiable, without implying additional production time. This is an agreement between three parties: the combat designers (Guilhem and myself), the programmer (Léo), and the producer (a position I also hold).
For our intentions, we wanted all the enemies to work from the same system, so all the "brains" of our enemies use the same structure, which can then be assigned to different "bodies", which will interpret the information differently. Moreover, we wanted to avoid as much as possible a global intelligence managing all the enemies in a fight. This is an arbitrary decision, it would probably have been smarter to manage all the enemies with a single brain, but we wanted a maximum of different situations to emerge, and it seemed logical to assign one independent (or almost independent) brain per enemy.
Finally, we wanted a system that encouraged the player to diversify his actions, and exploit all his skill set (jump, double jump, light, and heavy attacks, combos, roll). So we needed archetypal enemies, challenging on different skills, but also an artificial intelligence able to understand what the player was doing, so that the robots could modify their behaviors accordingly.
So, now that the presentations are done, let's start with AIs' parameters.
Each AI has a value in Aggressiveness, Defensiveness, Cunningness, Lucidity, and Reactivity. Which will allow it to react differently to game situations, and to be more or less sensitive to certain stimuli.
To that, are added the actions of the enemies: each of their actions (to move, to attack, to use a skill, to do nothing) has also a value of aggressiveness, defensiveness, and Cunningness. Thus, it is possible to determine that taking a step to the side is more cunning than attacking. Therefore, a cunning robot is more inclined to take side steps.
In addition to this, other decision-making parameters can be added, such as the presence of a cooldown, or an initial weight.
Next, all actions have their action parameters :
Temporality: Each action lasts a specific time, expressed in seconds, and is divided into 3 parts: A Start-up, a Climax, and a Recovery. In an attack, for example, the Start-up corresponds to the moment when the enemy raises his arms, the Climax corresponds to the moment when the arms come down to strike, and the Recovery is the time of inaction after the action.
Resilience: i.e. how well during the action the character will be protected from destabilization and other attack cancellations.
If the action is an attack, then the action has more parameters :
The damage of the attack
Its range (hitbox)
The destabilization of the attack: i.e. how much the attack will repel or stun the target.
These are just a few of the many parameters of character actions in Umbrellads, a more exhaustive list will probably be made in a future article on the combat system.
So for now, we have a character, who faces opponents with brains as well as actions. The next thing we need is to determine actions.
Determining Action Lists
Step One: Approach Phase
The player has different anchoring points around him.
The circle in the center represents the player, the points represent anchorage points, they are of three different colors, corresponding to the distance with the player (layer 0: the closest, layer 2: the farthest).
The robot, if it is not on an Anchor Point, first chooses the Anchor Point it would like to be on. A robot got a list of layers that he can be on (a robot with small arms can't go on Layer 2!). Then, the robot checks that no other robot is already on the point, but also that no robot has decided to choose this point. To this is added, of course, the prohibition to choose this point if it is inaccessible (in a wall, above the void).
The robot then has a list of possible actions, which we will call the Approach List (mainly movement actions). Most of the time you can find there: Move to point, Move against the point, Diagonal-forward move, etc. There can be duplicates: we can imagine a high-speed forward movement that lasts 0.5sec and a slow forward movement that lasts 2sec.
If the robot gets close enough to its anchor point, it interrupts its current action, and moves on to the next step:
Second Step: Close Combat Phase
The robot then has access to a brand new action list, called Combat List.
This list is composed of movements, attacks, and related actions. Movements are here on the player's referential: movement towards the player, movement away from the player, etc. Let's also note that all actions are allowed or not depending on the anchor point layer: we can for example imagine an attack that can only be launched on layer 0, a move that can only be made on layer 1, etc.
How are the actions chosen?
Now that the presentations are done, let's get to the heart of the matter: how are the actions chosen?
We use an adaptive weighting system: each action has a probability of being chosen depending on the current situation, it rolls a dice among all the possibilities, and so chooses the action.
The adaptive weight formula is as follows:
= (P + ( a(A + Pv * L) + d(D + Pd * L) + C * c)) * AC
Each term here refers to a parameter :
P = initial weight
a = sensitivity of action to aggressiveness
A = aggressiveness of AI
Pv = vulnerability of the player
d = sensitivity of action to defensiveness
D = defensiveness of AI
Pd = danger of the player
C = AI cunningness
c = sensitivity of the action to cunningness.
AC = attack cancel (see "Danger box").
L = lucidity
If the action is an attack :
Danger box: during the start-up of a player's attack, a danger hitbox appears, to indicate to the IA the upcoming attack. If an enemy is in this danger hitbox, when making a decision, the AC value is changed. Here is the calculation of AC :
TR : time remaining at the start-up of the player
SUT: start-up time of the AI attack
OT = TR + TR * Random(-0.5, 0.5) * (1 - lucidity) - SUT
If OT is positive, AC = 1 + OT + A
If OT is negative, RT
RT = total resilience - destabilization
If RT is positive: AC = 1 + A - D
If RT is negative: AC = 1 - D
If the AI is not in a danger box, or the action has no offensive hitbox, AC = 1.
Player Danger (Pd): If the AI is in a danger box, Pd = 1, otherwise, Pd = 0.
Player Vulnerability (Pv): If the player is in any other state than Idle/Walk, Pv is equal to the time left for the player's animation. Otherwise, Pv is equal to 0.
Actions that cannot be performed (not on the right Layer, cooldown action) have an adaptive probability of zero.
This formula may seem a bit abrupt at first glance, let's try to see what's behind it :
Let's break the formula down into 5 parts:
= (P + ( a(A + Pv * L) + d(D + Pd * L) + C * c)) * AC
1. "P" refers here to the initial weight of the action
2. a(A+Pv * L) refers to the involvement of aggressiveness in the action
3. d(D+Pd * L) refers to the implication of defensiveness in the action
4. C * c refers to the involvement of cunningness in the action
5. We are saving AC for later.
1. P
P is very simple to understand, it is just the initial weight.
2. a(A + PV * L)
"a" corresponds to the aggressiveness of the action. We multiply this value by A, which is the aggressiveness of the robot (so, the more aggressive a robot is, the more it will use aggressive actions). To this is added the vulnerability of the player (noted Pv), which is called the adaptive value. We can consider that Pv is the objective reason why a robot will choose to attack. Indeed, Pv is equal to the time left before the player can act again. So Pv allows the robot to decide to attack at the best moment: when the player cannot defend himself.
Finally, L reduces the importance of PV: a stupid robot will not think of acting based on PV.
Note that the more aggressive an action is, the greater the impact of PV.
3. d(D + Pd * L)
Very similar to the previous formula, but this time calculating the weight of defensiveness. The Adaptive Value here is Pd. Pd just allows us to see if the robot is in imminent danger or not. If this is the case, the weight of the action will increase greatly, favoring defensive actions when the robot is in danger. Once again, L allows here to reduce the importance of Pd: a stupid robot will not act according to Pd.
Note that the more defensive an action is, the greater the impact of Pd.
4. C * c
Calculate the cunningness here. By design, we wanted the system to be able to detect how tricky the situation is. But finally, we changed our minds, so there is no adaptive value here.
5. AC
AC allows robots to act according to the time of their own actions and those of the player, as well as to consistently interpret the destabilization and resilience of all actors in a fight.
TR: time remaining before the player's attack lands.
SUT: start-up time of the AI attack
OT = TR + TR * Random(-0.5, 0.5) * (1 - lucidity) - SUT
If OT is positive, AC = 1 + OT + A
Let's understand what this means, if OT is positive, it means that the robot knows that he has time to perform this action before the player hits him, we then give a big bonus to the final weight by giving a value greater than 1 to AC.
If OT is negative, we calculate RT
RT = total resilience - destabilization
If RT is positive: AC = 1 + A - D
If RT is negative: AC = 1 - D
If the robot doesn't have time to perform this action before the player hits it, then the robot will check if it can't simply decide to take the hit (without being destabilized) so that it can, in return, attack the player. If, on the other hand, the robot calculates that it will be destabilized soon, the total weight of the action is considerably reduced.
If the AI is not in a danger box, or the action has no offensive hitbox, AC = 1.
AC is capital in the intelligence of the robots. Indeed, we wanted the player to have reasons to use the combos he uses. Thanks to this system, robots can exploit the flaws of a player who launches random attacks.
Conclusion
Umbrellads' artificial intelligence system gives robots a personality, as well as creating exciting situations. On the other hand, I personally find the system not very successful and is for the moment a little wobbly in incorporating it into the game. Indeed, although today already, some robots systematically dodge the heavy attacks, or that others decide to tank a hit without flinching, I think that the system could have been exploited more efficiently.
Finally, if I am in the future led to conceive another artificial intelligence system, I will plunge more deeply into a group intelligence, making enemies take decisions as a group, with more coordination.
Anecdote: The robots' personality system (aggressive, defensive, cunning) was especially useful for Umbrellads, indeed, some robots have particular attributes (giant, electric robot, etc.). It was then very simple to modify their behaviors without having to create a whole new system.
Comments