Updated: Aug 22, 2019
I covered my cow AI last time, and for a while that was all my game had in it. Alien Cow Farm was always meant to shine as a local-multiplayer couch co-op game, but I guess none of my testers had any friends to play with because I just kept getting feedback that the single player wasn't very engaging. Jokes aside, I couldn't put off the AI for enemy UFOs any longer.
Before I get into behavior, let's talk about basic pathing. Cows can wander anywhere on the map with three exceptions: cows inside pens cannot come out unless they are lured, cows outside pens cannot go in without being abducted, and they should generally not collide with static obstacles like trees. Now, one of A*'s basic functionalities is carving out a NavMesh from your level by looking at the user-assigned layers your scenery is on. You can tell it to include or ignore certain layers. This was very useful for my third condition, but couldn't do much for my first two. The difference is that, just because I don't want cows to cross the force field border under normal circumstances, doesn't mean they don't have to be able to at all. If I tried to rely on A* only to set up my world, it would have to be all-or-nothing. Make sense? Since I can't have my cows locked inside or outside permanently, I had to just leave the "ForceField" layer excluded and write some handling code myself: when a cow collides with a force field during its normal wandering, turn back the way it came and pick a new destination in that direction.
My UFOs are different for two reasons: A) they hover, meaning not all ground obstacles that affect cows should also affect them, and B) the different variations have different pathing rules. COM4 needs to access his own force field and barn, but should be locked out of any other player's. After spending quite a long time looking through the docs and even contacting the dev regarding how to make B work, I determined that none of the recommended solutions would work in my case. I ended up just solving both in the same way, using additional NavMesh recast graphs. (Note that this came with an increased load time for each map, but as long as you're playing locally [i.e. not using a web build], it's still reasonable.) The multi-graph functionality is one of A*'s best features. Basically, if you have multiple types of units who should behave differently or have access to different parts of the map from each other, you create multiple graphs and assign each unit to the map you want. This can be as simple as changing radiuses to give a larger buffer zone around obstacles, or as complicated as using a completely different set of layers to block off areas. So each COM UFO has access to their own barn only, and additionally, they can fly right over the shorter environment obstacles like they're not even there.
The COM UFOs are more complicated than the cows because they have more actions they can take, enough to warrant creating a real state machine. These actions are also influenced by things like the chosen game mode and difficulty setting. Just as a for instance, COM UFOs will not openly attack players in any but the highest difficulty, and just like human players, they aren't allowed to lure cows in Frenzy mode. In general, the default state is SEARCH, from which they can transition into TARGET, followed optionally by LURE, then ABDUCT, RETURN, and DROP, with interrupts for SHOOT and STUNNED. For those last two, the UFO is either reacting to seeing another player or getting shot by them, and should return to whatever they were doing before as soon as the action is finished. As for the others, SEARCH involves just picking a random point on the map and flying there. Each UFO has a detection field (the larger green box in the image), and if a cow happens to trip it during SEARCH, the UFO goes into TARGET. Now it has a specific cow it's going after and readjusts its course towards it. If that cow was freely wandering, no problem, when the UFO is directly above it, it goes into ABDUCT and plays an animation that sucks the cow up just like a human player would. But if the cow was inside a pen, we rely on the smaller green box to detect the edge of that force field. When it's tripped, the UFO drops a lure. I left the inner box large enough so that the cow has enough room to come all the way out of the force field before reaching the lure, so the UFO can still get directly atop of it and abduct successfully. Once the cow has been acquired, the UFO RETURNs home, to a preset point within their own barn. DROP puts the cow down safely there, and the UFO returns to SEARCH to find the next one.
Not too bad, right? As usual, the hardest part was the error checking and looking for edge cases, making sure COMs aren't trying to abduct their own cows or chasing each other around after targeting the same cow even after it's been abducted. It's actually pretty fun to just sit back and let a game run autonomously, like a simulation, watching for issues to come up. My logging has gotten a lot better recently, and I've even started doing screencaptures so that I can go back and pinpoint exactly how I got into a bad state. I'm really happy with where all of this is right now, and I hope that my beta testers will like the affect that AI opponents have on single-player games.