I made a game for Scream Jam 2023 | Consignment

In 7 days I learned Godot 4 and participated in my first game jam in 10 years

An old hobby

It’s been over a decade since I last made a game solo (made in Flash CS5 if that’s any indication) and I haven’t used a proper game engine in years but with all the recent talk about Godot, it finally felt like the right time to get back into game development.

I took a look at Godot 3 a few years ago; however, I just couldn’t bring myself to sit down and learn it. I’ve since learned one of the best sources for motivation is to hold yourself accountable to someone else’s timeline which is why this year I decided to enter into Scream Jam 2023 and force myself to finally learn Godot 4.

In this post, I’ll be walking through the design and development of my submission, Consignment, so I recommend playing the game first before reading on.

Story iterations

With only 7 days to learn the engine and make my game, I had to keep the scope small. From the get-go, I knew two things: I can’t make art to save my life and I don’t have the experience to make complex gameplay. From this, I figured my best bet was to make the game 2D and to center it around interacting with objects rather than fighting, platforming, or puzzle solving. For the setting, I drew inspiration from some of my favorite games: Dead Space, Prey 2017, SOMA, and the original System Shock and chose a derelict space ship.

I felt my gameplay wouldn’t be all that interesting so I wanted to make sure I had a good story to keep people playing. I wound up spending nearly all of the first day just brainstorming ideas.

The solo saviour

My initial idea was to have the main character wake up from cyrosleep on a ship they didn’t recognize only to find the crew still frozen and the ship badly damaged. The intent was for the player to slowly learn how their cryopod had been transferred to this ship for delivery to a distant planet; however, an accident caused the ship to become damaged on the way. The damage prevented the actual crew from waking, leaving the computer with no choice but to wake up the main character instead. The player would have been tasked with repairing the cryopods to wake up the crew; however, they would have ultimately died in the process.

The ill-fated crew

The idea of a solo person sacrificing themselves to save the next seemed unique so I decided to explore that more. I changed the story to remove the passenger and focus only on the crew. To explain why only a single crew member could wake at a time, I had the idea that the ship could not re-freeze someone once revived and that it lacked the facilities to sustain thawed crew for the remainder of the trip. The ship’s computer would refuse to allow more than one person to be awake at a time since it was effectively a death sentence.

I wanted the game to have a strategy aspect so the story evolved to give each of them a different set of unique skills required to fix one or more systems of the ship. Some of these fixes would prove fatal to whoever performed them so players would have to learn which person was best suited for each task and in what order to do them. To further support the strategy angle, the player would be required to choose which character to wake next after each death.

I didn’t have time for a ton of content so I also wrote in a strict time limit to encourage trial-and-error replay. I had the idea that your ship had stopped in a faster-than-light shipping lane and would be obliterated by the next ship using the lane if you couldn’t move it in 5 minutes.

The realization

Four days into the jam, I couldn’t shake the nagging feeling that what I had written was less horror and more sci-fi drama. I was also growing concerned that the gameplay would be too frustrating for players as I don’t have the best track record for strategic design. Furthermore, I felt having a time limit would make the game feel less like horror and more like action. It wasn’t an easy decision, but I made the choice to massively scope-down the game and refocus on purely atmospheric horror from the perspective of a single character with an emphasis on feeling helpless.

I kept the lore aspects of the previous story but rewrote it to only play as the captain. The captain, Alicia, would awake to find the ship nearly destroyed and the chief engineer missing. Through computer terminals and announcements from the ship’s AI, Sentinel, the player would learn the ship’s cargo includes over 7000 people in cryostasis including the engineer’s daughter. The player would learn how the chief engineer was woken first to repair the ship’s reactor only to find that they could not navigate the ship out of the shipping lane as the bridge could only be accessed by the captain. The player would eventually find how the engineer had taken their own life to force the ship to wake the captain to finish the task.

With that knowledge, the player would then be required to navigate the ship out of the lane before it was too late; however, they would find the ship’s engines could not be started without rerouting yet more power from other systems. The player would be forced to turn off the ships’ radiation shields to start the engines and in doing so would bathe the crew and its cargo in a lethal dose of radiation. Rerouting the power would allow the ship to move clear thus preventing any future ships from meeting the same fate; however, the ship’s reactor would fail in the process leaving no hope for the souls aboard.

This became the final story for the game and was the inspiration for its name: Consignment.

The game's thumbnail featuring the remaining 3 crew members

Development

Art direction

I can’t art to save my life so I spent a good chunk of the first day just looking for free tilesets I could use. I found some really nice sets but none of them quite felt right to me. Every top-down asset pack I found had cartoonish characters which just didn’t fit the direction I was going for. Eventually, I resolved myself for what needed to be done and opened Aseprite to draw my own.

Shading and color choice have always been a problem for me so I wanted to start with as small a palette as possible. Scrolling through the default selections in Aseprite, the CGA high intensity option caught my attention. I felt the expectation for games made using the CGA palette would be much lower than ones using something like the NES or Atari 2600 palettes. I also liked the novelty of using CGA’s magenta for blood effects.

Fun fact: For most of the jam, the player character was just this sad little square because I was dreading having to draw a person

I still didn’t have time to draw a ton of tiles so I chose a top-down perspective that only shows the faces of north walls.

In Consignment, only north wall faces are visible

Games like the Legend of Zelda show all wall faces
Photo: https://www.zeldadungeon.net/

Audio

I don’t know much about audio and didn’t have time to record my own samples anyways so for the game’s sound effects, I used the FilmCow Royalty Free Sound Effects library. This library turned out to be the perfect fit as it had a ton of great ambient sounds as well as scifi effects.

I’ve always loved the computer voice lines from Prey 2017, such as those from Morgan’s Suit, so I wanted to give Sentinel a similar voice. I followed a tutorial for creating robot voices which got me pretty close but I wound up tweaking the steps a bit. For the final mix, each line was comprised of two tracks each with a copy of my voice but with different effects applied:

  • For track 1:
    1. Increase pitch 10%
    2. Add echo with a delay time of 0.02 and decay factor of 0.6
    3. Decrease pitch 20%
    4. Decrease pitch 20% again (adjusting once by more didn’t get the same effect as doing it twice)
  • For track 2:
    1. Reduce tempo 2%
    2. Add echo with a delay time of 0.01 and decay factor of 0.6

Something I found while mixing the audio was I needed to break lines up into shorter phrases. Applying a tempo adjustment to longer lines would cause the tracks to desync so much that you couldn’t make out what was being said. It also sounded odd during playtesting to have voice lines start with no introduction so I added a couple beep sounds from FilmCow’s library to the start of each line and adjusted their pitch to create an announcement chime.

Original voice sample
Final mix

Architecture

For being such a short game, Consignment has more structure than you might expect. The game is divided into two core scenes: main and ship. The main scene primarily handles switching screens, loading the ship scene, and spawning the player. Meanwhile, the ship scene is responsible for tracking game state. Nothing particularly noteworthy here; however, it’s the structure of the ship scene that I really want to discuss.

The ship scene is built very literally with it being comprised of several smaller scenes each representing one of the main locations from the game: the cryo room, the bridge, and engineering storage. Each of these room scenes has its own tilemap, audio queues, trigger volumes, and scripts. The ship scene itself only actually contains the hallway tilemaps and the logic to relay signals between the rooms.

The tilemap, doors, and props in the ship scene are just for the connecting hallways

The idea was to make each room fully self-contained in code and layout. The rooms know nothing of each other nor do they know how the ship scene works. They just emit signals when something significant happens and expose public methods to change their state (if applicable). Picking up the override codes from engineering storage is a good example of this segregation of duties:

Here you can see the "signal up, call down" methodology the architecture is based around

Aside from keeping game logic separated, this approach also made it easy to adjust the ship’s layout. Just drag a room somewhere, update the hallway tilemap, and I’m done. This made development a breeze since I could quickly test with rooms close together.

All of the rooms were next to each other for most of development

There are many different ways to structure a game with no one approach being right for every situation but this is certainly one I’ll remember for the future.

Reception

Of the 497 entries, Consignment placed:

  • #13 in Story
  • #22 in Sound Design
  • #42 in Enjoyment
  • #75 in Horror
  • #83 in Aesthetics

And WOW! I’m honestly shocked by how well it did and super thankful to everyone who took the time to play and give feedback.

I didn’t expect rankings anywhere near this high but I have to admit enjoyment is the most surprising. Given my gameplay loop boils down to just pressing ‘E’ a few times, I expected to score much lower than I did. While games like SOMA and Amnesia also heavily rely on so-called fetch quests, they have additional mechanics to keep the game interesting along the way like stealth. I suspect that had Consignment been longer, I would have scored much lower but as-is I think the short duration helps keep the game from feeling too stale.

Aside from enjoyment, I was also surprised just how many people commented about liking the art direction. It was especially cool to see people mention it taking them back to their DOS gaming days. I may just revisit this palette again in the future because of that.

If you haven’t already, I highly recommend checking out the other great games submitted to this year’s Scream Jam. Some of my favorites are:

Retrospective

The ending

My intent was for the horror to come from the player’s realization of being in an unwinnable situation with others depending on them to do something about it. I wanted players to experience the dread and regret of letting someone down and to punctuate it with a feeling of isolation and lack of control. Unfortunately, I’m not sure those themes came across how I intended.

By far, the most common feedback I received was from players not sure if they had “failed” the game or not. It’s one thing if a player feels conflicted about what they did but it’s a whole other problem when they aren’t sure if they completed the game. Not knowing could have left some players believing there were other “better” endings they just didn’t find which takes away from the theme. In retrospect, I can definitely see a few reasons why players were led to think this way.

For starters, the power-rerouting segment at the end looks too much like it has multiple solutions. In reality, no combination of systems can supply enough power to restart the engines without also shutting down the radiation shields. I tried to make this obvious by showing how much power was required and how much was available on the main computer; however, I don’t think this was clear enough and I suspect most players didn’t even know the main computer would tell them that. This would have been much clearer if the rerouting took place through an interactive menu with a real-time power readout and switches to let them experiment.

The result of re-routing power from every system except the shields

Furthermore, I don’t think the impact of turning off the radiation shields was very clear. I got the impression some players thought at least some of the crew/passengers survived. In hindsight, I had to lookup what a lethal dose of radiation was while writing so I shouldn’t have expected players to know just how deadly 8,000msv is. I tried to make this clear with the final message indicating “multiple cryotube failures” in the cargo hold but I don’t think it was enough. Forcing the player to reroute power from something more directly impactful like cryo storage may have been a better option. Alternatively, showing the immediate signs of radiation sickness on the player and other cryotubes may have also helped.

On a related note, I’m not certain I made it clear enough the ship was beyond hope of rescue by the end. Through the bridge computers, I was trying to convey how the ship had lost its communications array, most of its lights/beacons, only had a few days of oxygen left, and was 20 years away from anyone who could help it. Additionally, the ending sequence was meant to imply the ship’s reactor had melted-down and taken the hydraulics with it causing total power loss and sealed doors. Despite all this, I don’t think I did enough to build the world outside the ship to make it clear why nobody would be able to help.

The final moments of the game before the credits were meant to let the player reflect on just how final the ending is

Audio design

Some great feedback I got on the submission was to look into applying ring modulation to the voice to make it sound more robotic. Audacity didn’t appear to have a ring modulation effect built-in but I found a plugin for it online. It’ll take some time to learn how best to use it but I definitely like the effect it creates.

Original
With ring modulation

Code

Changing the game’s premise after I already started development left the final build with quite a bit of dead code for handling the character transitions. In fact, there is even an entire character select menu and death system built in that just never gets activated. Despite that, the code was actually pretty clean up until the last two days of the jam.

Then all hell broke loose.

The main problem is with the segregation of duties between the ship and bridge scenes. See, the ship’s script is what triggers all the random ambient sounds and screen shaking effects while the bridge is what animates the ending sequence. This sounded fine when I first designed them except I forgot two things: 1) the ship needs to stop playing random sounds when the ending starts and 2) the ending animation requires screen shaking. I didn’t have time to refactor the scenes so the ship and bridge wound up coupled by a complex sequence of signals the bridge emits to request different sound and screen shake effects from the ship.

Actually, the ending sequence is even more rough than that. The sequence isn’t made using Godot’s AnimationPlayer like you might expect. It’s actually built from a ton of sequential timers. I knew Godot had an animation player; however, I didn’t know it could control scripts and I didn’t think I had enough time to learn about it anyways. Now that I’ve had a moment to read about it, I know it would have worked much better than what I did.

These are just a few of the callback functions for all the ending timers

Wrap up

Overall, this turned out to be a great way to finally learn Godot and get back into making games again. Even after the jam, I’ve been tinkering with small projects in Godot and wanting to learn more. I’m already excited for my next jam and looking to enter another this winter.

All that said, I haven’t been sleeping on my other projects either. I’ve been working to learn FreeCAD over the past few weeks with the intent of shifting my half-scale pinball machine development over to it.