Our last installment covered my first, aborted attempt at creating an intelligent enemy, or at least an enemy that felt intelligent to the player while ultimately being predictable and exploitable. The previous attempt saw the enemies posting up in cover and peeking back and forth. This didn’t work, mostly because all enemies know at all times where the player is, so it’s jarring and very odd to see these guys for some reason not get it. It was actually funny how unintelligent they came off as, like the guys from Dumb and Dumber showed up, and didn’t know they were in a firefight.
I took a step back and asked myself how a reasonably intelligent enemy would behave if given some of the same basic tools common to various enemies. I decided to implement predictive/suppressive firing, and coordinated movement. I wanted the military police to pin the player down, flank them, and damage them, or at least feel like they were credibly attempting to achieve this.
In the context of this game, suppressing the player is equivalent to arresting the player’s movement. If the enemy can see the player, obviously just fire right at them. But if they can’t, we want them to fire at the first open spot they’ll be hittable at. If that sounds a bit confusing, just look at the picture below. The player is moving to the top of the screen, so the enemy fires appropriately.

I stored about a hundred frames worth of data tracking the player’s velocity, and averaged that out to predict where they were heading. As an aside, it made me realize the potential inherent in using this for firing patterns. For example, an enemy that starts off its burst firing straight at the player, then slowly moves towards where it predicts the player is going.

Player was moving down, which is why the image isn’t ideal.
My first attempt to program suppression/pinning fire was to add invisible markers to each corners of a pillar/cover square, and then use a sequence of cross products to figure out which corner was most appropriate to shoot at, with a bit more math to provide a little spacing from the corner so the enemy didn’t have their projectiles all hit the corner instead of flying by. This worked well if there was one singular pillar, but totally broke down when there was a collection of them. In this case, the enemies would fire past the one pillar blocking the player from sight, and directly into the next one.

I then went down another rabbithole where I tried repurposing the pathfinding system, since the corners of each block are already marked by the system. That system was more robust, but didn’t work for irregular geometry, and it was an extreme pain to churn through the list and find the most appropriate point to fire towards. There was also a very nasty edge case where the enemy would fire at an edge node, but their angle would be such that the projectiles would just hit a wall segment just behind that, achieving nothing and looking quite stupid. In order to solve the problem I realized that I needed to sample the areas right behind the wall segment, to make sure they were firing into an open enough area to pantomime suppressive fire.

Ignore the lines themselves, just think of the points.
Which is when the actual solution hit me. If we’re sampling the space behind the potential firing solution, then we can skip all the math involving box corners and whatnot. All we need to do is figure out the axis perpendicular to the vector between the enemy and the player. Then, move ourselves in small, discrete steps along this vector, on both sides, and test whether we could raycast to this point. If we don’t hit cover, then we’ve found our suppressive fire position. If we’re sampling too far, then we just accept that there’s no point to laying down pinning fire, and act accordingly.

This solution works equally well for irregular geometry

I really could have done better than these green markers.
Sampling solutions have a well deserved reputation for being somewhat error prone. Anyone who was gaming in the 90s remembers how easy it used to be to move through walls in pretty much every game. That’s because those games used a very crude collision detection algorithm that checked if you were inside of a wall at any moment in time. If so, they spit you back out. It should be obvious why speedrunners combining low framerates with high speed often lets them go right through walls. There are more sophisticated collision detection algorithms which take into account the movement of both entities over time, and can give perfect solutions to collision detection, although for performance reasons even modern games don’t always utilize them.
It surprised me that the harder problem was getting fireteam commands to work, although for less interesting reasons. I simply had a myriad of uninteresting bugs to work out with various aspects of the system, enemies not going into the correct state, the AI coordinator suddenly refusing to give out orders, handling an enemy failing an order or dying, annoying pathfinding errors complicating everything, etcetera.
The most basic idea was to organize the military police into one large squad, where only one police was given an order at a time. I over complicated this initially with different orders, before settling on the one singular order they ever receive being to move to a new position. Currently they just move right towards the last known position of the player, although this is subject to change. When they reach this spot, they tell the AI organizer that they’ve completed their task, and a new task is given.
My original thought was that the police ought to be more sophisticated than simply moving towards the player, instead moving as a team to box the player in. While I still think that, the results are fairly good even with this simple algorithm.
I’m not even close to done with these guys, although adding flavour won’t take nearly as long.

The next step is to take a page out of FEAR, and make the guys talk to each other.













