Note: This system is a work in progress. In part 2, I will discuss things that could be changed for a better result.
Goal: Create a multi-tiered AI that performs navmesh search operations distributed across many agents.
Description: For this system, I am trying to create an AI that would attempt to search every nook and cranny it could. Once a location is checked, it should not be checked again. This should create a systematic sweep of the entire area.
The AI should begin by using EQS to discover a location that has not been searched yet, and then the AI should go to that location, search it, and repeat this process until nothing in range has not been searched. The undiscovered point should be close to a discovered location.
The first step was to figure out the behavior I’m looking for. In this case, I want…
- A location on the pathing grid
- A location that has not been seen yet
- A location that is close to the AI
- A pathable location. That is to say that, while the roof of a house may be part of the pathing grid, it is not pathable because an agent cannot make it there.
- The areas to be searched are distributed among participating AI
This will be a 4 step EQS process.
#1: Set up a pathing grid generator in EQS. I chose 1000 range with 100 distance between points. There are some unfortunate situations where 1000 range with 100 distance between isn’t good enough. Be careful when making this too large as we are going to be using the data nodes as context points, and you will have many of these in the world.
For the context, you will need to consider something if you choose to do this as well. If you want this system to run in any situation with no prior setup, you will need to do a context check off of an existing actor. If you are looking to do this without a preemptive Data Node, you will need to use the higher level controller (or one of the lower level soldiers) as the context to do the EQS check off of.
In my prototype, I placed a Data Node (mentioned in #2) where the higher level controller spawns at, and I set up a context that returns all BP_DataNodes in the level.
#2: I need to somehow keep track of all of the points the agents have visited. For this, I created a Blueprint that I called BP_DataNode. This Blueprint was originally supposed to contain data (hence the name), but it ironically stores no information now and is simply used as an indicator of the spots the AI has scouted.
For this step, I did a trace test. I traced from the pathing grid node to the context (same context as last step), and I had bool match set to true, even though what I was checking was whether it was out of LoS or not. This test is a simple “Filter Only” test. Scoring does not matter, as I want to eliminate all of the visible nodes, not give +1 to the ones I can’t see.
#3: Now I did the distance check. I used the same context as the previous two steps, and I measured the distance from the node to the context with a “filter and score”, although the filter portion was only set to a minimum of 0.0. The scoring was set to an inverse linear system so that closer points were favored.
#4: Finally, I checked if a path existed. If the node is unreachable, it should be discarded. This is also a filter only result. This test is optional depending on how the terrain is built. In my case, there were rooftops that would appear on the pathing grid, but they were not reachable.
View post on imgur.com
This is the EQS I used to scout for undiscovered locations. The massive red downward arrow is pointing towards the initial data node (so that I could track where they spawned). The querying mode isn’t that important for it, although I prefer 25% to create minor variance.
The next stage was to figure out how I was going to distribute the nodes to the lower level agents. For this, I had the higher level AI perform the EQS, generate a node at the returned grid point, spawn a BP_DataNode, and add it to an array of nodes that have not yet been searched by an agent. This particular decision was made so that they all have access to the same list, and the list is synchronized.
The low level AI is very simple. It moves to its current target node. When it arrives, it asks the higher level controller for the next node. The low level AI has no decision making regarding which node it goes to. All of that is handled through function requests sent by the lower level AI to the higher level AI.
Here is the end result:
View post on imgur.com
The red arrows may seem clumped up, but the grey boxes are 4-room buildings to test functionality. All of the red arrows point to data noes that are out of line of sight of all other data nodes, and the lower level agents are being sent to systematically check each of those points.
If there are any questions regarding this system, please don’t hesitate to ask in the comments. While the comments do require approval, this is to prevent spam.
In the second post on this subject, I will detail the problems this setup has realizing the goal AI mentioned at the beginning of this post.