As one of three programmers I had two main contributions during the project. The first was the state-saving of the components within the game's world, such as the clues and polaroids. The second was the in-game board used for solving the mystery. Beyond these I built upon the other programmer's work such as refactoring the book, used as the the player's hub, to be less resource demanding. Later in the project I also worked heavily with quality assurance, assisting the graphical team in finding minor inconsistencies in the game's environment.
A key challenge in this project was designing data‑driven systems that allowed the mystery’s clues and board to be reconfigured without code changes. This ensured the designer could rapidly iterate on the mystery structure while keeping state‑saving stable and predictable.
Missing Picture is a short supernatural detective game set in the forests of Värmland, Sweden, in the year 1987.
Team: 11
Duration: 10 weeks (8 weeks production)
Engine: Unity
Itch-link: https://kevin-jernberg.itch.io/missing-picture
Repo: https://github.com/Azivast/Missing-Picture
Keywords: Unity, C#, Data-driven, Refactoring
The mystery is the main focus within the game, and our designer and game writer iterated heavily on it throughout production. This meant that the mystery-related questions posed to the player and the way they were presented were also expected to change multiple times. Since the board is where the player solves each part of the mystery, it had to be flexible enough to accommodate these changes. To support this I designed the board to be fully data‑driven, meaning that question layouts could be rearranged or redefined into several different combinations without needing programmer involvement.
The board's system is divided into 'chapters', which represent a separate mystery. In-game this can be seen in the transition between the tutorial and the main mystery, where all information regarding the last mystery is hidden when entering the new one. Each chapter manages its 'pages' and each page defines a specific question layout. The only defined requirement for a question is that the player answers every one with at least one polaroid. As a result, the structure allowed our designer to create both linear mysteries that unlock sequentially and multi‑page setups where the player can revisit earlier answers while solving their current one.
The player can only place the correct type of polaroid in each type of polaroid slot.
When a question has been answered correctly the board automatically swaps to the next one.
Clue-objects will remove their own outline if another object registered as the same clue has been collected.
The clues’ backend was a core part of my work on world state‑saving. It connects to the map, camera, polaroids, world objects, and the board, ensuring each system can access consistent information about every clue. Because the game spans multiple scenes that the player frequently moves between, the backend needed to be lightweight, stable and easy for our designer to work with when adding or adjusting clues.
To ensure this, I built the backend around Scriptable objects. This meant that our designer only needed to keep track of one component per clue to access the backend data, such as the name-identifier shown to the player when a clue was detected by the camera. Since each clue asset tracked whether it had been collected by the player, other systems did not need to save that information across scenes. Beyond this, I designed the surrounding systems so that our designer could use the same scriptable objects to control what in-world object was assigned to each clue as well as which clues could be used to solve each part of the mystery on the board.
The team wanted the player to feel free to photograph anything in the game's world, which meant the game had to potentially handle more than a hundred photos in a single playthrough. To support this without causing memory issues, I built the polaroid backend around a static list that receives data from the in‑game camera system. Each time the player takes a photo, the camera sends the image data and any detected clue information to this list. If a clue is detected, the image is also added to a static dictionary, and any older image of the clue is replaced to avoid duplicate polaroids. This kept the information available across scenes and made it straightforward for other systems to reference.
This pipeline also solved a major potential memory problem in the UI. The polaroid chapter in the book is a way for the player to browse through their taken polaroids, both while roaming the world and when solving the mystery at the board. Early versions generated a separate UI instance for each polaroid taken, meaning that there could be an immense amount of memory usage if the player took a lot of pictures. To avoid such a scenario, I rewrote the polaroid chapter to instead use one fixed set of polaroids which displayed the picture on a current index in the static polariod list. If the player hadn't taken enough pictures to fill out the entire page, the superfluous polaroids were hidden. This meant that the amount of memory used specifically for the polaroid chapter stayed consistent no matter how many polaroids the player decided to take.
The polaroid chapter in the book will only enable those of its polaroids that has a corresponding value in the polaroid-list.