Technically Clean
Project Info
Language: C#
Engine: Unity
Team size: 13
Time frame: 4 weeks
My role: Systems & Audio programming
GitHub: Click here
Itch.io: Click here
Project summary
For Technically Clean, my team was given the theme “Cleaning Checklist” and using that theme as a springboard, we wanted to create something relatable: Your parents have left town, giving you unsupervised access to the house. So what do you do? Naturally, you throw a party. All is going well, until the morning after - when they call you, informing you that - panic! - they will be arriving home early! Now, you have two minutes to clean up the entire house after yesterday’s wild bacchanal - what do you prioritize?
Taking a lot of inspiration from Overcooked, this is a fast-paced, hectic and arcade-y cleaning simulator. The player has to weigh properly cleaning up, which takes more time but gives more points, against quick-and-dirty solutions that save time.
I’m very proud of what we achieved in just four weeks of development, and we received great feedback. Technically Clean even got nominated at SGA 2022 in the categories Best Art, Best Narrative and Best Tech!
FMOD and Audio
During this project, I wrangled the FMOD integration for Unity in a group project for the first time. My main objective was making work as easy as possible for our sound designer, Erik. The first hurdle to get over was version control. We were using Perforce, and the FMOD integration updates its cache if you so much as look at it, so I set up the project to be a single platform build. This restricted use of our FMOD Studio project to just Erik, but that was a fine tradeoff.
All the cache files had to be set to be ignored by our version control too, but they had already been accidentally pushed once and so existed in our depot, which meant they would not be ignored. Simply opening the Unity project would update the settings cache and editor cache files. But the FMOD integration settings inside Unity had to be the same for all team members working in Unity. Okay, no worries - I ripped out all the cache files from our depot and included all the temporary files, cache files and the settings asset in our .p4ignore. The drawback was that every team member would have to set the correct values in the FMOD integration settings manually once. But at long last, Erik could get started!
With the setup out of the way, FMOD made working with audio extremely easy. All one-shot sound effects were handled using FMOD’s Studio Event Emitter component, which is super designer friendly. The component is just added to the inspector of whichever object needs to emit a sound.
However, the background music was a bit more complicated. Erik wanted to create a background music track with increasing intensity coupled to the in-game timer. While using the Studio Event Emitter component would technically work (you can add an additional Studio Parameter Trigger component connected to the intensity parameter) I figured it would be better to hide the implementation in code and tell him “it just works the way you want it” without having any additional components cluttering up the scene.
So I accessed the music intensity parameter Erik created inside FMOD through the RuntimeManager in FMOD’s scripting API and could set its default value as well as update the value every frame inside our Timer script.
Settings
Since I was already digging around in the sound, the team was okay with me taking responsibility for all the volume settings. This work became extended into me taking care of the entire settings menu and its different options like resolution, fullscreen, graphics quality etc. and making sure they were saved across sessions.
I split the initialization of settings into two categories, Audio and Graphics. The initialization methods would check PlayerPrefs for already existing settings values, and then update accordingly. All the options got their own setter, which would save a new value to PlayerPrefs based on player input in the settings menu.
Menu flow, objects and task stations
One thing led to another and while I was working on the settings I realized that we would have to make sure that the sound was disabled on pause, that the music reset properly between scene changes and that settings correctly stuck when applied. So I took charge of creating the logic for the main menu, the pause menu, the end menu and the transitions between them. Using FMOD made the audio-related work pretty trivial - I could access the buses through the RuntimeManager to pause, unpause, stop events and set parameters as required by our menu flow. The rest of the logic had to do with time, which PauseMenu took care of, or switching between scenes, a lot of which could be handled through the editor, which although time-consuming to set up in Unity was very easy to do.
We also figured that fundamental systems that should be used and understood by everyone are good candidates for pair programming. For this reason we elected to program our ChoreObjects (things like dirty laundry or dishes) and ChoreStations (objects like the sink, where the player cleans ChoreObjects) together, and found that it sped up our work considerably.
Takeaways
This project gave me a lot to think about. Audio-wise, it showed me that linear volume ranges are problematic in Unity, and that it probably is a good idea to make an audio utility class which contains functions for converting linear to dB and back, for use whenever doing audio work in Unity. The slider values compared to actual volume increase is still off in this project because I realized this too late.
Also, it was extremely educational to take ownership of the audio implementation and work together with a sound designer like Erik. We had to overcome some hurdles with the setup, sure, but it made it ridiculously easy when the time came to actually put sound events in the game.
I had to help our artists with version control a lot in this project. It definitely reinforced my opinion that time spent helping team members with technical issues is well spent. An important takeaway from this is to try to get a sense of what level of understanding the recipient is before trying to explain something. If someone is not at your level and you just assume they will understand what you mean instead of adapting your communication to them, they’ll just get frustrated.
The biggest takeaway of all, however, was just how effective pair programming can make you. Instead of sitting alone and staring at a problem, asking for help (especially hands-on help) from a fellow programmer can do wonders. It really felt like we became more than the sum of our parts when we coded together, and I made sure to bring this with me to future projects.