While I thought a lot about structuring the whole “tactical AI” thing, I figured it’s better to start working on something and figure things out in the meantime. I decided to implement the approach shown by Anton in this devlog (which I couldn’t find for the longest time). It unfortunately means that I need to manually place down waypoints, but I’ll keep it that way until I can think of something better.
The NpcPoint
class is quite simple, it’s just a Vector3 and a list of floats for each polar angle. I attempted using three traces (in 22.5 degree intervals) instead of one when generating a node and picking the minimum, but the result underestimated all distances and didn’t seem to help at all, so I kept the documented implementation.
Next step is to actually make the AI use these points. I implemented some simple idealness factors just to play around.
The AI did start using these points. However, they used them constantly (since any point with a score can be chosen), turning it into a ghetto version of the nodegraph. In addition, when using weights in the original system, nodes without cover is preferred over nodes with cover due to line-of-sight checking. The cover usage is also kind of bad due to the limited precision provided by polar angles.
The first change I made was to ignore any node that is providing zero cover. This makes the AI revert to the strafe-and-shoot behavior more suitable when fighting in open terrain.
Next, I attempted to increase the polar angles from 8 to 16, which seemed to improve cover finding by a bit. I’m unsure whether the increased cost is worthwhile, but I left the value at a nice 12 (30 degrees for each angle), which should be a happy compromise.
To make the AI actually use cover (especially full-length ones) in combat, I made them strafe around a tiny bit within the point. It’s not perfect, but the end result makes it seem as if the AI is popping in and out of cover to shoot.
To encourage cover use, I also made “distance to chest-height obstruction” a desirability factor. This makes the AI choose to hug cover more often, which should improve their general survivability.
All of the above behavior is only done for engage mode. In push, our desired outcome is a little different – we don’t care about cover and just want to get up and personal! Because of this, I elected not to use the nodes at all, and just keep on using the old system of “get close and strafe a little”.
So far, I think I’ve made some progress. There remains a lot of unsolved issues though. For one, I would need a system of saving these nodes to a file, and/or a system to generate them dynamically. Next up, an actual overall goal for the AI to achieve, such as a patrol route, or an attack vector. And at last, I have to actually make a game objective of sorts. Doing that will undoubtedly reveal a lot more issues, but breaking things is part of the job description, I suppose.