BoneFire Mayhem is a reverse tower defense RTS game created during my second year in DigiPen for a game project. I worked with an art lead and six tech programmers in charge of building a custom engine for the game. I took on the role of the design lead and product manager for the team, implementing all design and gameplay elements through a Unity prototype while overseeing the production of the custom engine. The project was structured into two parts: one where we would create a functional prototype for our game and the other where we would port over the game prototype to the custom engine made by the tech team.
Recognizing the challenge of working with a custom game engine developed from scratch, I prioritized a cautious approach to the game scope, aligning it with the combined capabilities of my team. This approach allowed for adaptability within the constraints of a nascent game engine. The RTS genre was chosen for its nature of having scalable gameplay elements, such as being able to create a range of characters using different property values of the same logic.
Communication with the tech team was key, not only the conceptual vision for the game but also the specific technical requirements required for realizing this vision within the custom engine. The gameplay loop needed to be achievable with minimal features, such that gameplay could be quickly established once its core features were implemented. This project provided a unique challenge to me which required prowess in both front-end and back-end game development.
At first, we wanted our game to be easy to play while having a strategic depth to its gameplay. Before, the player's only lose condition was to run out of time, and in order to make players strategize around that, levels had to force players into developing strategies to speed up their raid efficiently. The health pool had to be increased across the board for combat to be long enough, and levels had to be balanced around the traversal time across light as mobs could only be spawned in the dark. The line between too easy and too difficult was far too thin, which warranted a fundamental redesign to make the game more strategic and easy to balance.
Players could only lose the game by running out of time.
Mobs dropped their bones when they died, allowing the player to pick them up and redeploy them immediately. Players had "infinite" resources and there were no real repercussions to mobs dying apart from taking more time for spawned mobs to travel back into action.
Combusting a mob would set fire to those around it and refund all their bones back to the player, creating light in the process which prevented players from spawning within the area for a moment. However, this downside was negligible as players could always be spawning a constant stream of mobs.
Mobs no longer drop their bones on death. A new lose condition was added when players ran out of mobs to use. Bone pickups were changed to be automatic with number popups.
Spawn costs became a major factor for players to consider in their strategies. Mob archetypes could be established with low, medium, and high investment options, with each mob having its strengths, niches, and weaknesses.
Combusting a mob would only partially refund their bones back to the player based on their current percentage health. This added a new cost factor for its powerful ability to cause destruction or reposition mobs at will, highlighting the importance of effective mob positioning.
After implementing these changes, the roles and archetypes of each mob could be refined to be more distinct. As I implemented data collection in the Unity prototype, I could also collect data metrics from playtesters in order to fine-tune my balance numbers based on real data.
Buffed hound health from 7 to 9, cost efficiency ratio should be in between skeleton and wraith, so should only be slightly buffed.
Nerf wraith knockback from 30 to 15 to make it more vulnerable when fighting villagers in closer ranges.
Buff demon knockback from 10 to 30 to make it more self-sustainable when fighting villagers, attack duration from 0.3 to 0.2 to slightly increase overall attack speed, increased bone cost from 20 to 30 to make its role as a high investment mob more apparent.
Adjust mob target weights to make archetypes and roles more distinct:
Zombie from 1.2 to 1 to increase swarming effectiveness.
Hound from 0.8 to 0.6 to increase off-tank capabilities.
Wraith from 3 to 5 to make its stealth aspect more apparent.
In order to complement the slapstick nature of our game where the player plays as the evil necromantic assailant, the music would be cheerful and upbeat, yet give off a sinister vibe and a slight level of creepiness with the use of minor chords. Music references of a "cute quirky horror" genre were taken from Plants vs. Zombies OST and Final Fantasy 9 - Vivi's theme. We ended up selecting Halloween-themed music as it provided a balance between cheerfulness and horror. A night ambience soundscape was used to compliment the background music to provide it with more context as the game takes place during the night in a secluded village.
The RTS nature of the game meant that many audio sources would be playing at the same time. There needed to be a balance of sound and noise, and sound effects must be subtle enough to not be too overwhelming to the player. The collective output of each audio source added to the overall ambience of the game.
Each speaker icon is an audio source in the game scene
To reduce the level of noise, sound effect triggers were kept at a minimum. Certain triggers such as footsteps and attack wind-ups were scrapped during development as they were deemed to be too noisy. Sound effects were generally muffled in nature with a low volume to avoid overwhelming the player. A higher volume was given to sound effects linked to triggers of higher importance such as UI prompts and powerful turret attacks, to establish a level of audio clarity in a hierarchical order.
"Wouldn't it be funny if all our sound effects came from our mouths?" was my initial thought when taking on the audio design for the game, as it suited the comedic and over-the-top approach to our game art with derpy-looking characters. We ended up challenging ourselves by mic-recording all our sound effects, which also gave us more control over each sound effect in the game. Our mouths weren't as flexible to cover every sound effect we needed in the game, but the intended effect was well met.
Our audio was initially implemented through scripting with Unity's audio source systems. I created a sound card script that could be assigned multiple variations of audio clips. When playing audio from the sound card, a random audio clip is selected and played with a random pitch between the assigned minimum and maximum pitch value, with the volume of the assigned volume multiplier. The sound card system allowed each sound effect to be easily configurable and previewed within the editor itself.
As the nature of the game can contain many instances of entities playing the same audio clip, having a list of audio clip variants to play from combined with a randomized pitch allows sound effects to be more varied. The implementation of the sound card system also allowed the same audio clips to be reused in multiple sound cards using different pitch ranges. In the example below, the audio files for bone_spawn could be reused at different settings for BoneSpawn and FoliageTree.
Audio listeners were managed in audio groups such volume and pitch control could be individually managed within the game logic. With reference to the image below:
The player can adjust the game’s music and sound volume from within the game settings. This adjusts the volume multiplier of the “Music” and “SFX” audio groups respectively.
Having two music sources allows different music tracks to seamlessly fade to transition their volume over a duration. For example, “Music 1” plays the main menu music while “Music 2” plays the game music. When switching scenes from menu to game, the volume of “Music 1” will interpolate from 1 to 0 while “Music 2” interpolates from 0 to 1.
“Music” is also pitch-adjusted based on certain conditions. When paused or in the end screen, the pitch is set to 0.9 to indicate that time has stopped. When the player is short on time during the level, the pitch is shifted to 1.2 for the music to be played faster, giving players a sense of urgency as they race against the clock.
“Game” contains all sound output from gameplay audio. When the game is paused, this audio group is muted so that gameplay audio cannot persist when the gameplay is stopped.
“UI” is separated from other “SFX” groups and unaltered so that UI sounds can always be heard.
“Ambience” contains the background soundscape, and is muted during the cutscene.
As our custom engine was built towards the support of audio using WWISE as middleware, the sound card implementation was ported over to WWISE so that it could run in the custom engine. As WWISE already had all the features that I needed built-in, I just needed to set the audio settings accordingly.
The management of audio features and settings could be designed entirely in WWISE, including music transitions, EQ control, and RTPC with game parameters. Audio triggers were event-based such that the game logic only needed to handle where and when each event is called. WWISE even had soundcaster sessions for me to test these events on how they needed to be triggered without needing to build the project.
Game balance turned out to be a bigger challenge than I had initially anticipated. The intricate interplay between various systems and mechanics meant that even minor adjustments could significantly alter the game's overall dynamics. Many design revisions became evident only through extensive playtesting and iterative refinement. When addressing game difficulty, one thing I've learned is to start off with a high level of challenge and then refine from there. Starting with a difficult game encourages players to explore all available strategies and mechanics to overcome obstacles. Conversely, when a game is too easy, players tend to rely on a single effective strategy, neglecting other gameplay elements. By initiating at a higher difficulty threshold, I can not only ascertain the breadth of player interaction but also pinpoint potential usability, technical, or design issues more effectively.
But what about the custom engine? Well, that part of the project is a whole other beast fit for another case study. For now, I'll have to leave this off with a to be continued...