I’ve recently started working with the talented folks at Digital Tuna (creators of CoBots) on a new project for the course Big Game, the grand finale of our second year here at Campus Gotland. The game’s name is Mechropolis. It’s a first person action puzzle game in which the player is invited to explore a long lost underground civilization. The only remaining inhabitants in this derelict world are the robot servants still carrying out the orders of their vanished masters, blindly digging deeper into the planet.
Mechropolis’ core mechanic is something we’ve dubbed “Fusion”. The player is able to stun a robot, pick it up, and throw it into another robot, fusing them into a single entity that combines the characteristics of the other two. By exploiting these fused robots’ unique traits, the player is then able to progress through the environment.
My main task so far has been to implement the robot AI and fusion system. The AI system is a simple but flexible state machine with single purpose states (e.g. “chase”, “flee”, “attack”) that are tied together and transitioned between when certain conditions are met.
I’d like to tell you about one such state that proved to be an interesting little challenge: the “Flee” state. At first glance, it’s easy to think of this as the direct opposite of the “Chase” state. If we define chasing as “moving towards a target” that would then make the definition of fleeing “moving away from the target”.
Thanks to Unity’s built in navmesh system, both of these behaviors are a simple matter of a few clicks and a couple of lines of code. Chasing is acheived by just setting the navmeshagent’s destination to the target’s position. To make a robot flee from the player, we just set the destination to a point at a set distance away from the robot’s current position along a vector pointing from the target to the robot and we’re done! Right?
Well yes, and no. We’ve achieved what we set out to do, the robot moves away from the player, but when running the game, the robot does not seem very interested in finding it’s way to safety. It moves blindly in the opposite direction from the player and is easily cornered. The problem however, is not within the implementation, but in the definition of the word “Flee”.
So what happens if we change that definition from “moving away from the target” to “avoid the target”? What this means is that instead of setting the robot’s destination to a point in the opposite direction from the player, we want to set it to the point that is “safest”. The question is where that point is. Is it the spot on the navmesh that is furthest away from the player at the given moment? Or is it a spot behind a wall or some other sort of cover?
Thankfully, as the inhabitants of Mechropolis are simple minded robots, the demand on their seeming intelligence is not very high, which greatly reduces the complexity of this problem. Because of our tight schedule, I needed an approach that was fast to implement, but still convincing enough to give the robot’s some sense of self preservation. In the end, my answer to the question above became “a spot away from the player and out of an eventual corner”. The way I implemented it was this:
Two times per second, the robot samples the navmesh at eight points at a set radius around it, the point furthest away from the player is selected as the new destination. In addition to this, any point that is at a distance from the robot itself shorter than a threshold value is discarded. In practice, the robot now behaves much like before, with the addition that it avoids being cornered, which is just enough for our purposes!