Game Programming & Audio Implementation - Good Workers Are Hard to Find

“You all have captured being trapped in an office perfectly.”

“Actually enjoyed rage quitting. Wonderfully infuriating game.”

This past April I participated in a game jam with some GDC Conference Associate friends. The theme was “Trapped,” and our approach in a nutshell was a stealth collection game, in which you are an intern in an office who must avoid chatty and imposing coworkers. (Not based on personal experience, we swear, mostly).

I initially signed up to integrate the audio middleware (FMOD) and implement the audio in-engine (Unity), and ended up taking on more general programming and level editing tasks as well when it became apparent we were short-handed in that department.

Check out the game on Itch.io, and the repository on Github.

Good Workers are Hard to Find on Itch.io

Audio Implementation

We chose FMOD for our audio because the sound designers were comfortable working with it, it’s quick to get up and running in Unity, and it works with WebGL builds (albeit limitedly).

I integrated FMOD into our Unity project and coordinated with the rest of the team to have them install the FMOD plugin locally, then I set up our sound bank build folders in the Unity project, and set up a separate repo for the FMOD Studio project for the sound designers.

WebGL is a bit of a pain when it comes to audio. Most browsers block audio from playing until user-interaction. For this reason, we load the sound banks when the game loads, and begin with a scene containing only a simple “Run” button. After the user clicks the button, we can move into our proper main menu and play the main menu music. WebGL is also a single-threaded environment, which makes stuttering audio hard to avoid during heavy parts of the game and scene transitions. We alleviated some of this by having the music fade out before transitioning from the main menu to the level. In hindsight, increasing the audio buffer length in the settings and decreasing the maximum voice count may have helped as well. Here’s the async sound bank loader coroutine for the curious:

// List of Banks to load
[FMODUnity.BankRef]
public List<string> Banks = new List<string>();

void Awake()
{
    StartCoroutine(LoadFMODBanksAsync());
}

IEnumerator LoadFMODBanksAsync()
{
    // Iterate all the Studio Banks and start them loading in the background
    // including the audio sample data
    foreach (var bank in Banks)
    {
        FMODUnity.RuntimeManager.LoadBank(bank, true);
    }

    // Keep yielding the co-routine until all the bank loading is done
    // (for platforms with asynchronous bank loading)
    while (!FMODUnity.RuntimeManager.HaveAllBanksLoaded)
    {
        yield return null;
    }

    // Keep yielding the co-routine until all the sample data loading is done
    while (FMODUnity.RuntimeManager.AnySampleDataLoading())
    {
        yield return null;
    }
}

The sound designers and I kept it relatively light on the runtime effects, but still got to implement some fun behavior. Halfway through the “day,” the office ambience brings in a layer of increased activity and chatter, and the music (Jon Dare did an excellent job capturing the “office muzak” vibe) transitions from a mellower morning tune to a bit more energetic afternoon tune. As the player bumps into coworkers who assign them priority tasks, more energetic musical layers also come in, including a slightly disorienting pitch-vibrato’d layer if the player manages to rack up three concurrent priority tasks. For the variety of tasks, we implemented base UI-ish SFX for task progress and task completion, with an additional SFX layer specific to each task (watering plants, pouring coffee, etc).

The FMOD Studio project

Gameplay Programming

I also programmed some UI and gameplay elements, and organized/placed some of our task objects in the level. Implementing the UI clock, which triggers some audio and gameplay events, and the green arrow that hovers above task-related objects, was fun and sometimes infuriating. Working on the web of logic in our TaskManager and TaskSO (Task Scriptable Object) scripts, and using a service locator pattern, was also a great learning experience. So many weird cases, especially with our sticky-note-tasks-take-priority-and-block-your-base-tasks logic. There’s quite a bit there so I won’t post code snippets here, but you can check it all out on the repo.

All In All

It was a great experience working with a team of programmers and sound designers, collaborating over git, and hashing out ideas and implementation details together. I assumed a sort of liaison role on this project between the engineers and the sound designers/composer, and I really enjoyed contributing to both the creative design and technical implementation. It was interesting and enjoyable to represent the audio design team to the engineers (explaining why using middleware was in our best interest, why and how SFX and music should be implemented) and repping the engineers to the sound designers (keeping things in scope, runtime limitations and ways to design around them, like baking effects and consolidating layers that don’t need to be manipulated independently). Everyone on the team did fantastic work, and it was a real pleasure working on this project with them. More games to come.