Title: The Hungry Maw from Outer Space
Company: Team Cat / Futuregames Academy
Period: Developed as a student project during 4 weeks
Designers : 3
Engine: Unreal Engine 4
Responsibilities: Gameplay Programming ( C++ / Blueprint), Systems Design, Objective System, Human AI, Enemy AI, Optimization
The Hungry Maw is a game about destruction. The main goal of the game is to destroy a city. With more mayhem, military presence becomes stronger in the city and the goal becomes harder to reach. In order to keep destroying, the player may need to replenish health. This is done by beaming up humans to the Maw's mouth and eating them.
The objective system works by giving the player one main objective and 2 sub-objectives. Sub-objectives are spawned around every 30 - 45 seconds and give the player an additional challenge.
It is important that the objectives are very customizable so they are more unique and fun. I also used the objective system for the tutorial in the start of the game, not letting the player get any sub-objectives until the tutorial is completed. For this I had to be able to specify exactly what logic is run when an objective is completed, to create a sequence of interesting objectives.
I solved this with the creation of an event message system, where each process in the game can create an event and inform all processes of what happened. E.g. If an enemy tank in the game is killed, the process will send this message to the Event Message Dispatcher along with any additional information needed. In this case we also send what type of weapon was used to kill the tank.
The objective manager is responsible for creating and destroying objectives. When created, the new objective is responsible for hooking up its functions to the Event Message Dispatcher's delegates. This is so it will receive notifications of important events happening in the game. The Objective Manager is responsible for removing objectives once the objective is completed or failed. Objectives can then be shown on the HUD for a few seconds longer and are not instantly removed from the HUD.
Objective Event Handler
I created all the objectives in C++ code. This example shows a simple objective detecting an "On Tank Destroyed" Event Message and keeps track of the number of tanks destroyed. Objectives are complete when a set number of tanks has been destroyed and will then send another Event Message to inform the Objective Manager that it can prepare to destroy the objective.
Example of Objectives I made in the game
(Don't use reverse polarity gun.)
All delegates are exposed to blueprints for easy implementation in both visual scripting and C++.
In this example, I create a blueprint that keeps track of how many human have been killed or eaten. The current number killed is then printed as a message to the screen.
With delegates, I don't have to change any code at all in the human logic.
Example shows how easy it is to setup a new objective
What could be made better ?
In The Hungry Maw we needed to have a lot of humans running around. The player is supposed to eat them and regain health by doing so. Without knowledge of the limitations of the Unreal 4 engine and very limited time, this was one of the hardest parts of the project.
The humans need to react to the environment by changing direction when bumping into objects. They also need to react when the player is shooting at them, the humans flee in panic when something explodes nearby. Humans also have the ability to be crippled by falling off buildings or being released from the Maw's beam.
For a long time, we had performance issues with the humans. I used Unreal's profiler tool to discover bottlenecks. The first iteration gave each human a timer to keep track of when to update the logic, setting them to update the logic only at 30 fps. However the overhead of the timers was killing the performance. I instead used only one timer and an array to update all of the humans at the same time.
This worked a lot better, but we still struggled with performance, so I changed the array to use a doubly linked list instead. It was a lot better but still not good enough. My conclusion was that looping arrays in blueprints was very slow and it was necessary to move the code over to C++.
Human Update Logic
The logic for the humans is organized into priority arrays. In the Game Mode you can set how often each array should be updated and what distance that array is used for. This allows us to not update the humans far away from the player and saves a lot of performance. This also allows me to scale the humans very easily based on the hardware used.
The human's A.I. was first built in blueprints for fast prototyping. When I saw it was working as expected I converted the most heavy part of the code into C++. This increased performance drastically and was necessary to make the game function.
The main interface used is the Set Panic Modifier. This is used by explosions in the game. The explosions have a sphere trace around them and tells everything that implements the panic interface where the explosions occurred. As a result of this, humans turn away from the explosion and start to run.
I made sure all the optimization settings were exposed to blueprint. This is so that designers can experiment with different settings and see the result without having to recompile the C++ files.
Also the tutorial can easily be disabled by just setting a bool to false.
Example Human A.I. Code
What could be made better ?