This section describes in general the bot design. We will not go into detail here, because it would fill a ton of pages (and bore you!). All bots use a single prefab and structure for consistency.
EASE-OF-USE: Simply adding the provided A.I. FSMs to any GameObject with a Rigidbody, Animation Controller, Collider Trigger, and NavMesh Agent will give A.I. functionality to that GameObject.
MODULAR AND ORGANIZED: Although the Awareness FSM module serves as a central event trigger, modular FSMs and scripts run concurrently or are disabled individually to maximize customization and minimize performance overhead. For example, the Awareness FSM makes a decision to enable the Attack FSM, but the Attack FSM makes further decisions on its own whether to execute a Melee or Ranged attack, or even perform a dance right before shooting.
WHY THE FSM MODULES EXIST: All of the FSM logic and large web of State nodes ultimately serves the bot decision process in one of three ways:
- Outputting data to its other FSMs. (Environment awareness, detecting any enemies within sight range, remaining health, etc…)
- Receiving and retrieving this data from other FSMs, which can either be a bot’s own FSM or another bot’s FSM. For example, an enemy bot’s FSM might send damage data to be deducted from the bot’s health. Another example would be for a bot’s Attack Module to verify with its Awareness module that there is indeed an enemy within range.
- Processing data from #1 and #2, and, based on a set of rules in addition to randomness (for enemy variation), executing certain bot actions (such as running, dodging, shooting, chasing, etc…)
We have provided a bot template prefab with all required components included, ready to go. This prefab is in the folder “/AI Bot Structure/ AI Bot Base.”
Each FSM takes in input data from another FSM, makes decisions from this data, and outputs data to be read by other FSMs.
Each A.I. bot must have the following 8 FSMs to be functional:
The Attack FSM has 2 roles: 1) It holds the stats for the bot’s current weapon, such as bullet type, bullet speed, ammo remaining, etc… Damage stats are in the individual bullet prefabs. These can be changed at runtime for weapon switching. 2) Executing Melee and Ranged attacks.
It is activated by the AWARENESS FSM, from which it receives data about the current target. This module deactivates itself after it determines from the AWARENESS FSM that the target is no longer in range.
It outputs the following data: status_IsAttacking (bool) – Is it currently attacking a target? Example usage would be the Movement FSM checking status_IsAttacking to determine whether it can play a certain animation and not disrupt an attack animation.
This module constantly scans the bot’s nearby environment, with the radius of the scan dependent on Sight Range, Hearing Range, and Line of Sight. Upon “seeing” a nearby enemy, it will activate the Attack FSM, which will automatically attack the enemy. The Awareness FSM then goes back to scanning, letting the Attack FSM make decisions on its own. If an enemy is behind a wall or another object, the Line of Sight functionality will not trigger an attack. You can see this Line of Sight in action in the MASS BRAWL EXAMPLE SCENE. The first rows of fighters attack, but the fighters behind them don’t fire since their teammates are blocking their line of sight.
It receives the following data: Noise level from its nearest enemy, its own Tag, Melee/Ranged Attacks Enabled? (from Attack FSM variables).
It outputs the following: Closest enemy GameObject, distance to nearest enemy, Vector3 position of enemy, number of enemies/allies remaining, and whether an enemy is detected (bool intel_EnemiesRemaining).
CHARACTER NOISE FSM
Instead of analyzing actual audio data in real time (which can be a huge performance hit), we decided to create with a more simpler, faster way to detect real time noise. Every time a bot moves, it will generate an amount of Movement Noise (charSTAT_Movement_Noise). Every time it attacks, it will generate charSTAT_Attack_Noise. For example, if a bot is running, it might generate a Movement noise of 150. When it goes into stealth mode, it could generate a noise of 10. Same with the Attack Noise. If a bot is using a knife, it might generate an Attack Noise of 10. But once you equip it with a shotgun, it can generate an Attack Noise of 500. This might alert a nearby enemy bot behind a wall, that did not detect him initially due to Line of Sight. That enemy bot will now move towards the last known location of the noise to check it out.
This FSM takes in bool from the Attack and Movement FSMs, detecting whether the bot is currently moving and attacking.
It outputs Total_Noise_Generated, which, at any given time, a nearby enemy bot will take in as scan input to determine whether the total noise number is within its Hearing Range threshold, taking into account, the Vector3 distance between them.
HEALTH AND DAMAGE FSM
This FSM takes care of maintaining the bot’s health stats, receiving damage, armor/damage reduction, deciding whether to run away on low health, and executing destruction effects.
Setting charSTAT_GodMode to true makes the bot invincible.
This FSM has a public function, “TakeDmg” that can be called either by enemy bot’s or projectile bullets. Out-of-the-box, this framework is designed so that the individual bullets call the “TakeDmg” function of the victim it collided with, and sends over the determined damage amount (random damage range). On the other hand, Melee damage is usually sent by the enemy bot himself. Check the prefab, “Demo_Bullet_Yellow” and its FSMs on how its done.
This FSM outputs the following bool: runningAway. It sets this to TRUE, after detecting that the bot has health reduced below 30% (editable), and resets both the Movement and Tactics FSMs with new orders. Since the Movement FSM checks the runningAway bool, it will block all future commands and will only attempt to leave the battle area.
This run-away feature can be turned off by setting “charROLE_RunAwayWhenLowHP” to FALSE.
This FSM doesn’t actually do anything, other than hold identifying data for the bot, such as its name, gender, occupation, etc… Feel free to add as much as you’d like. The only variable name you should never remove, is charSTAT_Name, since the Bot Nametag Add-on depends on this.
It takes no input data from other FSMs.
It outputs data such as charSTAT_Name and any other info.
The Movement FSM takes care of the following:
- Retrieve the current command from the Tactics FSM and executes that command. (For command details, see the BOT COMMANDS section)
- Divert from its current mission, if needed, to chase a nearby enemy.
- Process waypoints (Sequential waypoints, looping waypoints, pingpong waypoints, random waypoints, etc…)
- Patrol nearby area
- Guard current area
- MoveTO a specific location or object (such as a flag, in a Capture the Flag game)
The Movement FSM takes up the most processing power. That is because the characters in most successful games are constantly moving, whether they are allied fighters, enemy guard patrols, or neutral townfolk NPCs. Even a bot standing Idle in GUARD MODE has its Movement FSM constantly scanning for new commands because in a fun game, the situation is always fluid. This makes a game more interactive and realistic.
TIP: In some games, you may want characters that do not move. The correct way to do this is to set the TACTICS_CurrentCommand variable to “GUARD_HOLD_POSITION” in the Tactics FSM. SEE THE TOWER DEFENSE EXAMPLE SCENE on how to do this. Do not uncheck the Movement FSM thinking that it will make your bot stationary!
RANDOMIZE STATS FSM
This expandable FSM randomizes the bot’s stats as soon as he is activated in the scene. Use this FSM to randomize pretty much any quantitative aspect of the bot, such as running speed, response time, health, armor, etc… It helps you to create character variation for a more realistic feeling.
It does not take in or send out data to any other FSM.
It modifies variables in other FSMs.
This FSM is concerned with tactical changes in a broad sense. It holds the TACTICS_CurrentCommand string which is what you want the bot to do at the current time. It comes with many pre-built commands. (More on that later)
The default FSM does not take in data from other FSMs, although a modified version of this can be seen in the CAPTURE THE FLAG EXAMPLE.
It outputs data, namely, the current command. Other FSMs constantly refer to this command in order to make decisions.
Primarily, the MOVEMENT FSM reads the TACTICS_CurrentCommand variable. Thus, if you wish to change the bot command at run time, say, from “GUARD_HOLD_POSITION” to “PATROL_WAYPOINT”, you need to change the string to “PATROL_WAYPOINT” and reset the MOVEMENT FSM. This can be done either by calling the global “Reset Movement FSM” function in the Tactics module, or by manually deactivating, then reactivating the Movement FSM.