The Long Arm of the Law is a 3D action-platformer set in an Old West environment populated by robots. The main character is Motor Rockwell, a sheriff-bot who’s hunting the gang of bandits who stole one of his arms. Ordinarily, sheriff-bots have two extendable arms that can reach out and grab things, but since Motor had one arm stolen, he has only one of these. As a replacement for the one that got stolen, he now has a smaller arm that he uses to wield a pistol. This combination of two different mechanics creates enjoyable gameplay opportunities: you can use the extendable arm to grab a wall, pull yourself up to it, and shoot enemies from higher ground; you can use the arm to pull yourself around a room for quicker movement; and you can swing around a grabbable point on the ceiling and rain down hell on your enemies from above. It’s a lot of fun.
It’s so fun, in fact, that I am thrilled to announce that Long Arm of the Law won awards at the Intel University Games Showcase in March of 2019. Of the more than twenty student teams presenting student projects and vying for awards, our team, Quality Games, walked away with awards in not one, but two categories! We won 2nd prize for Best Gameplay and 2nd prize for Best Visual Quality!
This was an amazing and thoroughly enjoyable project to work on, and I want to thank Intel for giving us this recognition, and to everyone else on the team for making the game as great as it is. For our first big project, I think we knocked it out of the park!
As the lead A.I. programmer on my team, I engineered the behavior of all the standard enemies in the game.
The first enemy I created was the TNToad, a frog-like enemy that would hop around and chase the player. These robots are bombs, as the name implies, and when the TNToad gets close to the player, it blows up and hurts the player character. When creating this enemy, I had to learn about all the A.I. tools that Unreal Engine 4 provides: A.I. controllers, behavior trees, blackboards, decorators, tasks, services, and NavMeshes.
The first thing I had to tackle with this enemy was getting it to recognize the player. In doing this, I learned about UE4's AIPerception component, which proved very helpful and is something I am using for all the enemies I'm creating. This task also required the creation of a state machine and a related enum to capture the enemy's current state, another system I am using for all of my enemy types.
Next, I had to make the character jump, which I accomplished by using the LaunchCharacter Blueprint node. After that, I used SetActorRotation and FindLookAtRotation to turn the TNToad after every jump to face the player. These two steps combined to create an enemy that constantly hopped toward the player, regardless of where he was. Unfortunately, this system doesn't automatically work with NavMeshes. This meant I had to create my own system for querying the NavMesh and having the TNToad stay within it.
The final important step in creating an intelligent jumping enemy was to ensure it could jump up onto ledges. I needed to make sure that the TNToad wouldn't just stop when faced with a low wall it could clearly jump over. In order to accomplish this, I set up the TNToad's jumping logic to traverse those links. I also collaborated with level designers to place them in areas in the game where TNToads would be commonplace.
The second enemy I worked on was called the Miner. This was a robot miner, with pickaxes for arms, that would run toward Motor whenever it could find a direct path, swinging its pickaxes along the way and doing melee damage to Motor if he were to come into contact with it. If, on the other hand, the Miner could not find a walkable path to Motor, it would tunnel below the ground and use that to make its way to Motor, tunneling up walls and onto ledges if necessary.
This was, by a considerable margin, the most difficult enemy to program. At nearly every step of development, it always seemed to have something wrong with it. First, it would get stuck in the ground when it tried to tunnel. Then, its pathfinding started to fail unexpectedly, causing it to tunnel when it shouldn’t have. At one point, I managed to get the Miner to get fully below ground to start digging its way to Motor, but I had forgotten to turn its gravity off, meaning that without the ground collision to keep it up, it fell into the void. There were all kinds of other glitches, too, most of which were hilarious to watch (I wish I’d recorded footage of these; they’d be great to look back on now). Thankfully, by the time the game was finished, I ironed out all the issues this enemy was having and got it to work as intended.
The most interesting feature of this enemy was, in my opinion, the method by which it found an underground path to Motor. Erian, the lead programmer on the team, created a tool for me to use that would create custom navigational meshes on solid surfaces. I could place a 3D volume in a scene, and wherever a solid surface appeared, the volume would generate a collection of waypoint objects, placed close together and connected to their immediate neighbors, which I would then use to plot a path from the Miner’s position at that time to Motor’s position (I used Dijkstra’s algorithm, if I remember correctly). Erian, incidentally, now works for Microsoft, and given that was able to produce this tool that blew me away, it’s not hard to understand what they saw in him as a job applicant.
The final enemy I created was called a BandiTurret. Originally, this enemy’s design was very different from what ended up being its final design. It was originally simply called a Bandit. When Motor shot a Bandit or entered its field of view, the Bandit would run to the nearest bit of cover, hide on the other side of it, and peek out from behind the cover occasionally to shoot Motor with its shotgun. I put a considerable deal of work into implementing this original design; I was able to create a system that would determine the nearest usable cover, determine which side of it the Bandit should hide on, run to it, and occasionally raise its head and gun above the cover to fire.
Then, scope started getting cut. We simply didn’t have enough animation man-hours to get a the model rigged and create animations for all of the different actions this character would take, so it was decided to replace the Bandit’s legs with tank treads and rename it the BandiTank, which would cut down on the amount of work our tech artist and animators had to do. Then, the scope had to be cut even further, and the enemy was thoroughly redesigned.