In a programming-based independent study, I modified the behavior of the AI provided in Unreal Engine 5’s Lyra Shooter Example Project to make use of cover and search for the player within multiple states of alertness.
Utilized Unreal’s behavior tree system to shift between states of moving to and shooting from cover, repositioning in response to being flanked, and transitioning between high and low-alert patrol states.
Crafted a ‘hivemind’ object to enable AI controllers to update each other’s awareness, distribute cover and patrol points, and exchange brief vocal interactions upon state changes.
By default, Lyra NPCs behaved like standard arena shooter characters, running toward enemy targets and simply shooting and strafing until one participant in the duel was killed, rinse and repeat. In order to modify the Lyra NPCs to utilize cover, I needed to break down the concept of cover shooting into every action I wanted my NPCs to perform, as well as the conditions in which to perform those actions. These included finding and then running to cover, peeking from cover to fire at the player, relocating if their cover was flanked, hiding if they needed to reload, etc.
Once I had those actions defined, I needed to construct the technical foundations for performing them, first tackling how to identify cover and whether that cover was safe and in line of sight of the target. My solution was to create a "cover object" I could align with surfaces I wanted enemies to utilize. The cover object contained data on its orientation in the world, whether it was long enough move along, and a reference to any character occupying it.
When searching for a new piece of cover, the NPC would cycle through cover objects in the arena and check whether they were flanked, already occupied by an ally, in line of sight of the target, and closest to the desired distance from the target out of the other options. This decision-making process resulted in an intelligent selection of cover to move toward, and with the inclusion of the occupation check, naturally prompted flanking behavior.
Once the logic for selecting and moving to valid cover was defined, it was pretty straightforward to assemble a behavior tree around that prompted dynamic, lifelike behavior. Soon, NPCs were peeking from cover to fire, moving to new cover after a set number of peeks or when line of sight was lost, moving along cover and reloading when hidden, and strategically repositioning while laying covering fire when flanked.
Next I wanted to add another layer of believability and strategy by implementing the ability for NPCs to lose sight of the player so they themselves could be flanked. The Lyra NPCs already had a system for detecting whether a target was in their line of sight, so I initially built off that, creating a "target" object that snapped to the player character when visible to a member of the enemy squad but remained stationary when not. This "target" functioned as the player's last known location that NPCs would position around and shoot when the player disappeared from their collective knowledge base. Problems arose when it became increasingly evident that Lyra's premade vision check for the behavior tree system was not intended for use with cover, as the visual blockage that came with it made finding the target too difficult and losing it too easy. Clearly, my cover shooter AI would need more than physical line of sight to track the player through cover, while still needing a way lose track of the player.
My workaround was to trigger the initial detection of the player through the existing vision check or when taking fire from the player, then relying on a line of sight to the player's currently used cover, if any, for vision. If both those methods of vision failed, the enemy squad would continue to track the player for a few more seconds before the "target" object stopped following the player, upon which the enemies would hunt the object instead. If the player didn't reappear after a few seconds of attacking the target object, the NPCs would start a patrol in search of the player, having at this point completely lost their target.