Oliver Nyholm
AI and Gameplay Programmer

Specialisation



AI | Influence Map | Navmesh Baking | Learning | Troop Formation


I did this cinematic sequence a lot during production with epic music in the background

About the Specialisation


TLDR: With help of an Influence Map that could modify a navmesh in runtime, a God AI would send troops in formation towards a fortress with a goal of breaching the defense and attacking it's runestone.


The specialisation was the final course at The Game Assembly where we had 100 hours to specialise ourselves in a game programming field and create our webpages. I put around 80 hours into the specialisation.

I have the project on Github if it is of interest.


Initial Goal


When deciding on what I wanted to do for my specialisation, I knew it was AI. But what I wanted to do was unknown. I was in this spotify period where I was mostly listening to soundtracks from Lord of the Rings and World of Warcraft. This inspired me, with the picture of Uruk-hais attacking Helm's Deep, to create a "God AI" that could send units running in formation, trying to breach a fortress. I wanted to make something that looked neat.

I decided to use Unity as game engine. Since I was quite experienced with Unity, the engine would not hinder me in my work. I was keen on trying out Unreal again, but then there was a risk of my specialisation turning into trying out Unreal more than AI. As I wanted it to be somewhat cool and not code with capsules, I used assets from the previous project, Spite - Ragnars Mjöd, and created some own models in Maya.


Problems and Solutions


Influence Map

The god AI didn't have a Saruman telling weakpoints in the defence and ladders to climb over walls with. I needed something for the AI to figure out which part of the defense was weak and better to attack, something to read from when "learning". The solution would be to use an influence/heat map to collect data from. I created a grid for the Influence Map to store data whenever a unit damage an object, a unit died or an object was destroyed. This data was transported via a postmaster system that I also created for the project.

After each attack made by the god AI, the influence map would place out navmesh modifiers on areas that are unwanted or prefered to walk upon. After placing, the influence map would rebake the navmesh in runtime, creating these areas.

Destroying the tower gave a lot of good influence 
                    around the tower that previously was red after it had killed a lot of troops

The enemies chose to walk through the crag
                    instead of pushing towards the front gates since there was a weak spot
The function that gathered the different types 
                    or messages sent to the influence map
Influence Map in Inspector. I like to have 
                    debug buttons so I can test one feature at a time

Navmesh

Although I've had issues with Unity's navmesh in the past, I decided to use it as it would save me a lot of time. The scene had two navmeshes, one for the formation generals that would move the formation, and one for the units to walk upon. The difference was for the formation generals navmesh, as it was for a broader agent and would rebake depending on the influence maps data. When rebaking the navmesh, the troops would either avoid and walk around areas where there previously had been a lot of casualties, or walk through an area that had shown success.

The influence map would place navmesh
                    modifier volumes (Boxes) that would influence the navmesh

Unity however didn't have an option to calculate the cost of a path with the areas crossed, so I had to do that calculation myself, with help of the influence objects (boxes in image) placed by the influence map. At each corner of the path to available targets, I would raycast to the next corner when calculating the length, adding modifier values depending on the area cost.


After being rebaked, there were areas with
                    different cost to walk on
The God AI would try to find a path to each 
                    target in the scene
Calculation the distance to each target. 
                    I chose to divide with 10 to increase the value of walking on prefered areas.

Decision Making

The God AI would do the grind work. It would tell the influence map to bake the navmesh, send out troops and do data calculations. The AI would send out two formation generals with 30 units each to the best target. The calculation of the best target was the part that took the longest to work on. There were a lot of numbers and different "fitness" values that needed to be tweaked. And then I was a bit silly and created a big map, which could have long distances to run. This resulted in longer simulation times.

First move, with a roar the AI sends away troops to a 
                    tower with less health than others.

The final recipe for the best target was the one that had the least amount of failure, biggest threat, most damaged, highest value, best area value and the shortest path cost.

  • Least amount of failure was the score given when attacking that target object. Damaging would give bonus to the target, while dying would reduce the score.
  • Biggest threat was given to towers that defended the base and counter-attacked. When they killed a unit, they were given a threat score. If they had killed many, it was important to prioritise and destroy that target.
  • Most damaged was simply the current health percentage of the target, with a multiplier of the value of the target.
  • Highest value was given to objects with importance. Walls were low priority, whilst the runestone has the most.
  • Best area value was calculate from the influence map. From the targets position, the area around it would determine if there had between success in that region before. Or failure...
  • Finally, the cost of moving to the object was taken into consideration. With the influence on the navmesh, some paths were considered "long" to walk and had a lower priority than paths where there had been success.


Whenever the troops succeeded or failed (they all died), the God AI would do a new calculation to determine which target to attack. The algorithm was as follows. Influence Navmesh -> Rebake Navmesh -> Calculate best target -> Send out Troops -> Wait for result.

The God AI tried multiple solutions, with the best 
                    solution being destorying the left most towers, being out of range from the other towers and squeezing through to the runestone.
The best target was calculated with a bunch 
                    of different variables for the targets. This function took the most time to tweak to get favorable behaviour

Formations

As my main focus wasn't formations, I started of creating them early with simple positioning. I had a Formation General that handleded the pathfinding to targets. The formation general had a list of units, and depending on which formation the general used, it determined their positioning and made them move to those positions. I tried a bit with steering behaviours making them avoid each other, but decided to only use it while attacking, as it looked better and more smooth when they could clip into each other when running to their formation slot.

Unity has a built in Agent obstacle avoidance, but I turned it off as it freaked out the general when the units were close by, which was always. This caused units to detect obstacles only when close by, trying to move around them afterwards. I didn't see it as a big issue, as my simulation map didn't have really tight areas and much collision avoidance.

Possibility to switch between formations. 
                    Formations were saved as scriptable objects, so I could modify them in runtime whilst also saving them. Troops walking in formation through a narrow edge.

Result


Night mode made it more exciting when reaching the 
                    runestone.

The result of the project was a God AI that eventually would crack the gates and reach its target. I am overall pleased with the result, most happy of reaching my goal of creating something that looked neat! I had a lot of fun moving around and following the characters whilest listening to epic music. When I added the final touch with night time, it got even better!

I've once again learnt that working with AI takes a lot of time balancing, trying to find the values that make it look good. Especially with the "learning" AI, I could have been tweaking variables for ages. I found it difficult finding a balance of what the correct behaviour should be. Honestly, the troops could run into the same direction over and over again, eventually cracking the base, with no casualties taken into consideration. That, however, would not have been fun at all.

If I had more time, I would have definitely created some troops on the defending side, creating close combat battles. My initial plan was also to have ranged units, but I cut them from the plan quite early as the project already had a high scope. When the enemies attack, they all kinda clump together, fighting to find a spot where they could attack. This could have been solved with a feature where they would wait for their turn to attack. Also, it would have been nice and more of a "battle simulation" to send out troops in intervals, instead of only sending out two troops at a time and wait. And finally, of course, tweaked a lot more on the decision making variables.



Following the AI in night time was even better.