The Last Light

The Last Light is a first-person horror game for the PC where you play as Sophie, a high school student, who is desperately trying to reach her brother.

Your only hope for survival is your flashlight and other light sources you find along the way.

Good luck, you’ll need it.

The Last Light on

The Last Light Steam Greenlight Concepts page



The Last Light was created with a very small team as my college capstone. Thus, my primary tasks were always changing, as I was helping write code wherever was needed, however, I wrote a lot of the UI and Sound. Secondary tasks included general bug fixing and co-coordinating the task list of the programming team with the needs of the design team.

The Process

The Last Light was built in Unreal Engine 4, and thus the UI used Unreal Engine’s Unreal Motion Graphics (UMG) for the majority of design and layout, with Blueprint visual scripting filling in the gaps. This kept scope (and unfortunately challenge) relatively low. The sound work was mostly handled by Unreal’s systems as well, but the subtitles and sound options required a bit more effort, most of the work still being handled by Unreal’s Blueprint visual scripting.

The challenge that these two systems posed, however, came from the way that they interacted with other game systems. The in-game HUD component in particular caused quite a few headaches due to the way that it needed to interact with the inventory system in order to display relevant information, like the currently equipped weapon and it’s remaining duration or power. Not knowing much about that particular subsystem, it meant that creating interfaces that didn’t exist took much longer than usual, because I had to make sure I understood everything about a particular section before I started appending changes to it. This was to make sure that I not only didn’t insert any errors (logical or otherwise), but that I also didn’t break any encapsulation principles that were necessary for the system to work. This caused me to rethink the assumptions that I made when making the UI system and even caused me to  redesign some of the routines in the UI to make them more readable and expansible. An example of this was creating events for whenever the UI updated or received an event that would require something in the UI to change.

However, this change in thinking came with challenges of its own, because I didn’t want to be frivolous with additional interfaces. I think that I found a happy medium in creating events for things that I believed that other members of the team might have needed and just making the code readable (in organization, naming conventions, an commenting), thus allowing them to create their own interfaces as needed. This sentiment ties into one of my secondary duties as a link between the designers and programmers, as this frequently sent me deep into systems that I didn’t fully understand in order to create interfaces (usually accessors) for the designers, and at some point while doing this it dawned on me that it would have been nice to have events set up for these actions/values to begin with so that finding them later was as simple as registering a listener or calling a single function.


The Last Light has been officially released, and while I have my gripes, engineering-wise it could have turned out worse. While I didn’t necessarily gain a lot of factual knowledge or evolve much academically, I gained a lot of valuable insight on the practical side of programming. I learned the importance of a lot of good fundamentals and how my code affects not only other members of the programming team, but potentially the teams of other disciplines as well. I feel like The Last Light helped me massively improve as a game developer as opposed to just a programmer.

As one final note, here are a couple of other things that I’d learned over the course of making The Last Light:

1) A classes’ constructor runs when the object is created within the scene. The BeginPlay event is called when the game starts. This is an important distinction. While working on The Last Light, the team has had a bunch of volume classes that crash the game when the player starts the game spawning within them because there are missing properties of the object that the player interacting with them attempts to access. This results in Unreal 4 throwing an access violation exception. Make sure that all of your code is safely prepared for this distinction.

2) Realize what objects have collision and how they affect the collision of your game. Use collision layers where necessary. We’ve had tons of collision problems, and a lot of them boil down to the improper use of physics. The player can pick up objects through walls because the only prerequisite to picking something up is that is touches the invisible collision interact volume. Dropping a flare usually causes it to bump off of the player. Scripted sequences trigger too early because the player’s invisible interact volume  is considered part of the player’s actor and they are both on the same collision layer. Do not make this mistake as we did.
3) Dialogue is expensive. Files are big, decompression is a bitch, translation and subtitles are required, audio balancing takes forever, and all so that players can call the writing crap and trash talk the performances of your actors. Unreal’s default attenuation settings are not usually great for small, interior spaces, and so custom attenuation properties should be one of the first things that you should do. Audio volumes are also important, place them as soon as possible.
4) Physics is not perfect, and thus, you will have to compensate for it. Flares frequently fall out of the level through the walls and floors, because they are thin static meshes and the physics calculations will often overcompensate and let objects pass through them. Be careful how you handle empty and padding space for your world when converting over from BSP.
5) Static Meshs are your best friend. BSP is not final, and it is fairly expensive (performance wise) as compared to static meshes. Meshes in Unreal 4 also have collision meshes auto-created when imported, but this is not always perfect. We spent a very long time debugging elevator doors because a solid collision rectangle was created for the static meshes for our door frames.
6) Unreal 4 is blindingly pretty; don’t get caught up in all of the bells and whistles.
7) Unreal 4 is not perfect. Features are frequently still in development or not well optimized. The Environmental Query System is very helpful for AI programming, but is tagged “experimental” and still has some bugs that we cannot particularly fix as a small team. Unreal’s UMG UI also had bindings for certain elements that monitor certain fields (like attaching a from the player’s health to a progress bar), but they aren’t terribly efficient and Epic even recognizes this in their documentation. Know the extent of your tools.

The Last Light was a student collaborative effort involving a lot of talented people. Too many to list individual websites. Please see the page for a more complete accreditation.