A karaoke-powered fighting game
Just the Facts
      - A rock-paper-scissors style fighting game
      -  Who wins is determined by data from each player's singing
      - I authored all programming and design
      - The first version was created in just three weeks
      - I revisited (and refactored) the project a few months later
Tools Used
      - Unity
      - C#
      - Cinemachine
      - Timeline
      - Various assets from Mixamo and Freesound.com

The current version 

(which uses placeholder audio for the players' inputs that was pulled from covers of Somebody Told Me so that I don't have to embarrass myself any further while playtesting)

First Attempt
This project began as a mad dash to create and submit a game to the GDC Alt+Ctrl showcase that focuses on games with alternative controllers. The idea came about when the producer of a video game podcast I was listening to mentioned that they thought it would be cool to see a game that somehow used karaoke as a metric for a fighting game. The other hosts on the show seemed to think the idea was a bit far-fetched, but I had an idea for how I might pull it off, so I immediately messaged the show and asked the producer if it would be alright with him if I gave it a go. He gave me the go ahead, and I started work immediately with less than a month before the Alt+Ctrl submission deadline.
I knew the game would likely never be "sellable" since it would require getting the rights to a boatload of expensive songs, so I mostly viewed it as a way for me to further develop my skills in Unity while also creating something that would hopefully end up being a fun party activity. My basic idea was to split the song into "phrases," at the end of each would be an opportunity to choose a fighting action: attack, block, or leg sweep. Each player's move would then resolve by either dealing damage to the other player, preventing damage from being dealt to them, or breaking the other person's block and gaining energy (Star Power) towards a special move in the process. Then a new phrase of the song would begin, and the gameplay loop would restart.

Block beats Attack, Leg Sweep beats Block (thereby increasing the sweeping player's Star Power), and Attack beats Leg Sweep.

Using the rock-paper-scissors set up for a fighting game is certainly well-trodden ground, but rather than rewarding players for their timing and their ability to read animations, Karateoke rewards players based on how well they sing. By gathering data from each player's microphone input and comparing it to the vocals from the original song, the game determines which player is giving the best singing performance. That player would then be the only one to deal damage should both players attack.
My hope was that this would create a situation where each player was simultaneously trying to gage how well they're doing, how well their opponent is doing, as well as what their opponent's plan of action might be. For example, if player 1 thinks that they've obviously pulled ahead during the current phrase, they might think that player 2 is planning on defending against their imminent attack. Therefore, it might benefit them to choose Leg Sweep rather than Attack so that they can break their opponent's block and gain some Star Power. Conversely, if player 1 believes that both players are confident in their own performance, it might be worth it to choose "attack" and see whose singing comes out on top.
My first pass at the game's basic functionality was finished right before the Alt+Ctrl deadline. This included: 
    - A combat system
    - A lyric scrolling system that could trigger different game states
    - A tool for placing the lyrics (both horizontally for timing and vertically for pitch) using a script
    - Tools for determining each lyric's timing and pitch values (for placement)
     - An audio system that would listen to the player's inputs and compare it to the master audio
I would have been the first to admit that it was far from perfect, but I was happy to have taken an idea from concept to functionality in a little less than a month. And while the project was not selected for the 2020 showcase, I was satisfied that I had something that I could rework into a game that would closer resemble what I saw in my head.

First demo, finished at the end of November, 2019

My second attempt at building Karateoke included:
    - A completely restructured and refactored combat system
    - New animations (and new logic for executing those animations)
    - More VFX (including simple particle effects)
    - Decorative audio visualizer "sound bars"
    - A rotating main scene camera that changes its speed based on how long the current phrase is
    - Additional animations for the choice countdown
    - Simple text animations
    - Post processing to create a VHS look
A few months after my first attempt, the pandemic began, and I decided to use some of my newfound free time to revisit Karateoke. At this point, I had been working full-time as a C# programmer for just under six months, so it was safe to assume that my programming skills had improved quite a bit since I had first started working on Karateoke. This was proven when I reopened my scripts and was faced with a monster of a refactoring job. Fortunately, getting the project's scripts into a more logical and optimized state was a very satisfyingly process. I refactored the entirety of the combat, the animation, the Star Power moves, and the camera logic.
The first version didn't do a great job of visually communicating the results of each combat encounter. The animations didn't flow into each other properly and didn't convey what each person had chosen. It was a bit unclear what was happening and why. This was largely due to the fact that all animations were being triggered by the same script where the results were determined. This meant that if player 1 chose "leg sweep" and player 2 chose "block," the game would determine that player 1's sweep beats player 2's block, and player 2 would immediately go into the "falling" animation. The person playing as player 2 would never see their character actually perform the action that they had inputted, since the system was only showing the combat's result.
For the second version, I wanted to change the logic so that player 2 would go into their block animation and have their fall animation result from player 1's leg sweep. So I separated each player's actions and reactions into their own scripts so that they could react to each other's moves. I no longer had one "combat script" that served as a puppet master for every action each player took. Of course, this seems like a very obvious solution to me now; but that's partially why I feel this project is a great example of learning through doing.
There were a number of other improvements made to the combat code, but the most user-facing change was the decision to space the combat farther apart. The first version, while still fun in a mad-panic kind of way, was a bit too frantic in how it resolved each combat phase at the end of each phrase. It was also too difficult to strategize or really pay attention to what was happening since everything was moving so fast. So I made the decision to reduce the number of phrases, thereby increasing the length of each phrase. This way, the game lends itself more to giving a strong karaoke performance than to simply button-mashing.
Cutscenes and Polish
In addition to reworking how animation and damage was determined in-game, I also added multiple elements of polish, especially to the Star Power moves. Previously, the star power moves were fairly lack-luster, largely due to my original time constraint. They had zero camera effects, minimal particle effects, and overall very little to make them feel engaging.
To remedy that issue, I invested some time into using Cinemachine and Timeline to create short cutscenes that seamlessly integrate themselves into the gameplay whenever a player reaches full Star Power. I also created a short quick time event that gives each player an opportunity to "save" themselves should the other player gain full Star Power. 
For example, if player 1 has full SP, then the QTE begins and each player gets a button prompt on screen with a ring around it that they must fill by button-mashing. Player 1 must defeat player 2 in at least two out of three QTEs in order to execute the SP move. But if player 2 wins twice, the move doesn't happen, player 1's SP goes back down to zero, and gameplay resumes. Additionally, if player 2 wins just once, then the damage that the SP move inflicts is lowered slightly, but the SP move still occurs. And if they don't win any of the matchups (which is certainly possible since player 1 is given a head start), they take the full brunt of the SP move.
I ran into a few obstacles in pursuit of making these cutscenes flow seamlessly from the regular gameplay. For one, the animations I used weren't set up in a way where I could just start them from where the character models were already situated. For both the attacker and the attacked animations to line up with each other, both characters needed to be set to the same position in the worldspace. So, to avoid any issues I might run into while trying to maneuver both character models to the same spot, I simply created an identical environment with separate character models that would only be used for these cutscenes. That way, I can simply activate those models, cut to their location, and then cut back to the regular game view when the cutscene is done.

Star Power QTE (activated when a player fills their Star Power meter)

Star Power cutscene (after a successful QTE)

I still have more I want to do with this project, including (but not limited to): finding better sound effects to replace my placeholders with, adding more visual effects, increasing the quality of my existing particle effects, and 3D printing a game controller that will attach to a microphone stand. But most importantly, my next step is to improve the gameplay through playtesting (and adding some more songs so that I don't have to keep listening to the same song over and over and over). Additionally, now that some time has passed since I began my second attempt, there is some refactoring that I'd like to do to my original refactoring (which just seems par for the course). But overall, I'm incredibly happy with where this project has gone and with where it's headed.
Back to Top