AI Behavior

Souls of Verdun

The goal for the enemy in Souls of Verdun was to create a single invisible, indestructible chaser. To achieve this, I needed to make a pathfinding object that could chase our player, trigger a jump scare, and implement other behaviors.

Immediately I started by using Unity's Navigation system and creating a class with a simple finite state-machine. I started with a crude prototype in which a capsule constantly sets its pathfinding destination to the player. But before I could continue, I needed behaviors to implement.

I opened a discussion with my team to figure out what we want the enemy to do. We decided that the enemy should wander around the map to attempt to search for the player. This would lead to more unique gameplay as the enemy would not always be in the same areas and would approach the player from different angles. We agreed that there needs to be some way to combat the invisible chaser, and came up with a proximity indicator and a way to stun the enemy to allow the player to get away. To fit our theme these became the compass and the flares in the game.

To begin my process for development, I designed a chart to outline the flow of my state-machine. 

I had an additional state for triggering events. Upon realizing that it wasn't logical to have an event trigger state in our game, I created the chart below to outline how an event trigger would run. However, our timeline did not enable for the implementation of these events.

To begin development, I made my finite state machine. I used an enum to define states, a switch state function, and a behavior function that runs every frame to run state specific code. It turned out that the behavior function was near unnecessary, as I used coroutines to run my looping behaviors.

The code below is the function I wrote for switching the state of the enemy and show only 2 of the cases as the others read very similarly. 

On Awake, the enemy populates its local variables with values on the GameSettingsManager I made to easily tweak values of gameplay. These values dictate when to trigger different behaviors on the enemy. Shown below, I made the inspector designer friendly with the help of NaughtyAttributes and Unity Tooltips.

Below are two Coroutines I wrote for wandering and waiting, that are started when the enemy switches into the respective state.

Outcomes

This project gave me a good opportunity to make an enemy AI. My code has much improved from previous projects, and I'm proud of where I've come. But with that said I have more to learn. After development of Souls of Verdun, I was introduced to abstracting state machines into separate ScriptableObject classes to clean up the main class. I would also like to find time in the future to learn new types of AI.

Collaborating on this project with my group pressured me to comment all of my code. Doing it in a consistent manner is really helpful I have found from reading other people's code and I began to do it myself.

Making the Enemy AI gave me the opportunity to make jump scares for the first time, and allowed me to learn more about features in Cinemachine. This project gave me good practice with Unity Navigation and finite state-machines. To read more about the AI I have made, click here.