I have been working on the prototype of Predator Simulator since February 2015. It’s a closed loop game, where the player is a predator chasing around innocent victims that are unfortunately stuck in the same level and getting eaten 🙂 I was getting tired of working on Caribbean Odyssey and this was my little getaway project. In other words, some work to get away from work. Well I also took a 2 weeks vacation with my significant other to a beautiful island in Thailand, so life wasn’t that bad at all. After coming back from the vacation I worked on the prototype for a few more weeks and the game was complete. There’s a lot to cover. I’m going to go through some of the main gameplay/AI features I had to implement. I’m not going to talk about player, camera, effects or level design, but more of the game mechanics and NPC/enemy interaction with the player and how the endlessness is achieved in the game. All done in Unity engine, C# language.
There is a fixed amount of population in the city (usually 15) at all times. Whenever an NPC gets eaten or dies, the OnDeath() event triggers a CountPopulation() method and checks if the population is lower than the constant (15). If so, it calls a SpawnPeople() method which spawns an NPC around the player in a random SpawnPoint at a random distance (5~20 units)
The Predator has quite a large area to run and its divided into two parts. Forest and City. There is a funnel path between these two locations with two Trigger objects. Whenever the Predator is changing location, a ChangePlayerLocation() function is called, which disables the NPC group in wherever the player is coming from. In the forest area, there are only animals and in the city there are people and enemies. While changing location, the CountPopulation() method is also called to check if there are more NPCs needed in the currently active area.
Random missions are generated based on what type of NPCs are active in the level right now. There are 4 different types of missions. Eat, kill, survive (for minutes) or find stars. Missions are not skippable and each time player finishes a mission, some amount of Coins and Diamonds are rewarded. The mission objective numbers get higher as the player gets to higher defcon levels, making it tougher and longer to complete a mission.
The predator will chase the NPC and they will run for their dear life. Must run towards opposite direction the player is coming from. They will keep running until a safe distance (20 units) is reached and predator is not around.
This system is for NPCs that have guns. So they are actively seeking a target to attack. When the predator is in shooting range (20 units) and within the viewing angle (which means in front) the enemies will chase down the predator and shoot at it. If the predator is too close (less than 5 units) then they get scared and try to run away towards the opposite direction. Also, if predator approaches them from behind and gets too close (less than 5 units), they get scared and try to run without trying to defend themselves.
Instantiating objects at runtime is quite expensive so the game tries to keep dead NPCs in a pool of inactive objects whenever the NPC is dead/eaten. When SpawnPeople() method is called, first it checks if there are any dead NPC object exist in the pool. If it does, then the dead NPC is taken as the new character and called ResetCharacter() method and we got a fresh new NPC to spawn again without instantiating. When no dead NPC found, the SpawnPeople() function simply instantiates a new random People prefab and makes it a child of object of the NPC pool. These NPCs are move to the dead pool on death, d’uh.
Whenever the Predator hits an NPC, the Ragdoll rigidbodies are activated and main character collider is disabled. Also, a mild force is applied to the Root bone of the NPC towards whichever way it got hit from. Creating the perfect effect that the NPC flew away after getting hit by the Predator NPCs are controlled by the Unity Navmesh agent. When they get hit, its important to suspend the agent and reset the path when re-spawned a dead NPC.
There are two ways to eat a dead prey. On mobile devices, a dead prey can be tapped and a simply raycast checks for a hit on the Ragdoll bones layer. If found, a small force is applied to the Root bone of the dead NPC making it float up a little bit, this gives feedback that the NPC was tapped and the Predator jumps towards the dead NPC. When Predator is close enough (less than 2 units), the dead NPC body’s Root bone is attached to a Transform close to the Predator’s mouth and a Vector3.lerp function is called to shrink the NPCs body size. I found out that only scaling down the root causes the whole body to shrink. A blood Particle System is played from Predator’s mouth making the effect that the NPC is getting eaten and shrinking in size. There is a eat speed factor float variable that controls the speed of the Lerp function, so bigger NPCs take longer to eat. Once the NPC Ragdoll shrinks to 0.2f size, the NPC is disabled creating the effect of disappearing in the Predator’s mouth and Predator gains some health points depending on which NPC was eaten.
This is just like wanted level in GTA. Every time an NPC is killed, the Defcon meter gains some value and fills up towards the next level. The Predator has a limited time (3 seconds) to kill another NPC to start a chain kill. When a chain kill is activated, the Defcon meter gains more and more value, reaching higher levels quickly. When NPCs are killed in a slower pace, the Defcon meter does not fill up that fast. Reaching higher defcon levels start to spawn higher level characters. Ex. Hipsters start to spawn at level 3, hunters start to spawn at level 5 and so on. Defcon level does not go down and as the level climbs, more and more lethal enemies start to spawn so the game gets tougher. But higher level NPCs have more coins to offer when killed/eaten. This balance was very important to keep throughout the game.
For some sadistic reasons, a Predator chasing down people and eating them while they are running for their life, is a lot of fun and sometime they fight back and kill the Predator too. This unpredictable dynamics between the predator-prey interactions create hilarious moments and I had my magic moment of “AHA!” and put a screenshot button right at the fingertip if iOS players. Pressing the screenshot button freezes all the living things (NPCs, Predator) but keeps everything running. Which I found was a much better looking situation for taking pictures. The player can rotate the camera 360° and take a Screenshot from any angle. And it literally looks like The Matrix! Screenshots are sharable through twitter, facebook, iMessage and emails. I also had to make sure that the name of the game is branded in the screenshot. I used the ReadPixels() function in Unity instead of the RenderToTexture() because in render mode the branding can not be done without a watermarking process which would be too complicated and might get too heavy on the mobile device, who knows. The end result was amazing! I even patted my own back after it was done because that is a neat feature heh heh.
There are 3 ways that the Predator can die. Starvation, Caught in a trap or Shot by hunters. Also the toxic fumes from the sewers in the city area are harmful but not instant killer. Every time the Predator dies, player can choose to continue at a cost of a few diamonds or restart for free. Restarting resets the defcon level to 0 and takes the Predator back to the start point (the cave). Diamonds can be found in various hidden corners in the game world or earned by finishing missions. There is also a “Watch ad to earn diamonds” option, like Crossy Road.
There is a lot more that’s going on in the game than just these, but this sums up how the basic idea works, and personally I think this is a very simple game. The project took me about 5 weeks including testing, bug fixing and creating the publishing content (screenshots, trailer etc). I hope the launch will be just as exciting as the development was. Gotta start on my other game by end of this week.