The Night Shift
Overview
This was a GMTK game jam project which I worked on for 2 days in July 2023 in a team of 3, where all of us did programming and art and music between us.
The theme of this game jam was "Roles Reversed" where the idea was to make a game where you played from a different perspective to the typical perspective of a game of that genre. We decided to create a stealth game where the player is the guard in a museum and robbers try to break in throughout the night shift to steal the paintings and statues.
It is the most polished jam game I have worked on to date in spite of the development time being the shortest.
Enemy spawning and AI
Enemies are spawned into the game from one of 5 locations, these being the windows found at the top, left and right of the map, the door at the bottom or the vent at the centre. Each time an enemy is spawned, a sound is played corresponding to either a window sliding open, a door opening or a vent opening to help the player identify where the enemy has spawned from to capture them. Directional sounds allow the player to distinguish between the three windows. Spawn locations are chosen at random for each spawn and the time between spawns begins at around 15 seconds but gradually reduces as the game progresses to increase difficulty over time.
The enemies use a state machine to determine what they should be doing at a given point in the game. When they are first spawned they select a target exhibit to steal. Originally, this was the closest exhibit as the crow flies, however, in testing this proved to make the game too difficult so enemies select an exhibit at random to steal. Once they have an exhibit they reserve it so that no other robber has the same exhibit target when they enter the building. If all exhibits are reserved when the robber enters, they start in casing mode. In casing mode, the robber will select a target tile in the museum at random to head for. Every time they have to make a turn in their path on the way, they check to see if any exhibits have become available for reservation, if one does they switch to looting mode and head for that exhibit, otherwise they continue to their target. Once arriving at their target they again check for reservations and if all exhibits left are reserved they select a new destination at random. In looting mode, robbers pathfind to their reserved exhibit. If the player catches them on the way, they release their reservation and are despawned. Once a robber arrives at an exhibit, they pick it up and switch to escape mode. In this mode, they pathfind back to their spawn location. If the player catches them on the way, their exhibit is returned to the place it was stolen from and the enemy is despawned, however, if they successfully reach their target exit, they despawn along with the exhibit. Catching an enemy is as simple as keeping the enemy in the flashlight cone for a few seconds.
The game uses a custom render pipeline to allow the environment to render everywhere but for the enemies and exhibits to only render in the player's vision cone. This meant that when we decided to add a visual indicator to enemies to indicate how long the player had looked at them and how much longer they needed to look at them in order to catch them, this was a great challenge. As we wanted the visual indicator to be some sort of exclamation mark, similar to the one found in Payday 2 when the player is detected, we would need to use a sprite mask and make it compatible with the darkness layer present in the game so that the exclamation mark would only appear in the vision cone. As this would essentially use two sprite masks layered on top of each other a custom render pass would need to be added to the custom pipeline and none of us were sure on how to implement this. Several failed implementations lead to situations where the exclamation mark would be visible only in the dark or the exclamation mark mask wouldn't work correctly and the exclamation mark would be clear and the box around it would be filled instead of the other way around. Eventually, I came up with the idea of cheating how the exclamation mark would work. I decided to use a sprite mask of the exclamation mark and then placed a solid colour image behind it. In the code which counted down the time the player had been looking at the enemy, I then added some code which would scale this solid colour image along the y-axis slowly filling up the exclamation mark. I also set it so that the colour of this image would change from green to red over time. This means that when the player first spots an enemy the exclamation mark looks more like a green dot, but over time it transitions into a red exclamation mark, at which point the enemy is caught. If the enemy enters the vision cone to start this process but then leaves without it completing the solid colour image is rescaled to make the exclamation mark once again invisible.
UI and Menus
I also played a large role in the creation of the UI and menus in this game. I began by refactoring the codebase so that the entire game uses pushdown automata to switch between menus and the playable game state. I then set up the buttons and sliders to switch between the menu screens and game states as well as control the volumes of the different sounds and music present in the game. My last task for the UI was to make the score visible to the player and to set up a timer which would trigger an end state of the game after 2 and a half minutes.