Trials of the Rift
Trials of the Rift is a top-down, competitive couch co-op party game. Two teams of two local Players each control wizard apprentices completing a series of challenges to earn the rank of master. The team which completes every room of their dungeon first is the winner, but players must also contend with the Rift, a magical entity separating the two teams from each other.
Play Trials of the Rift as it was at the end of winter quarter. Four dual-stick game controllers are required to play. Move and aim using the thumbsticks and cast spells using the bumpers and triggers. (If you don't have four controllers, you can use the spacebar dev hotkey to skip through the menus to get to the main game.)
Following the prototype's push to demonstrate core functionality as quickly as possible, the rest of fall and all of winter quarter were dedicated to development. We utilized bi-weekly sprints in order to deliver a series of "Playables", game builds which would then be tested by both the GMAP Team and external playtesters. These playtests provided feedback on the game's design and whether or not it was actually fun to play, but the most valuable lessons learned on the CS side were about project management: workflows needed to be defined explicitly, documents like the GDD needed to be kept up-to-date and unambiguous, and we couldn't accept new feature requests once a spec had been finalized without cutting short testing time and lowering the deliverable's overall quality. The GMAP Team needed constantly reminded of this last one.
As System Design Lead, I was responsible for taking the GMAP Team's requests and translating them into pseudocode, determining where and how to implement each new thing into the codebase. Several design decisions were made at the very beginning of the project, and they informed everything we did since. Probably the greatest of these was the decision to make use of the Object-Component design pattern and the rest of the Unity paradigm, both for our familiarity with it and the advantages it provided to game design specifically. We got functionality like all the built-in Monobehaviour methods and auto-updating of template-like prefab instances for free. We also decided to use object pooling for our Enemies and Objectives (to save on resources), to not use an Event Manager (to follow good OOP protocol), and to handle all in-game collisions with extensibility in mind. When two GameObjects collide, the event message is sent to both. Our rule was that our “static objects” like The Rift or Players should change as little as possible, so instead any new GameObjects added (like when new Objectives were created), would receive the handling code to interact with the ones that already existed. This way, we were always adding new code, but rarely modifying anything already-written, following the Open-Closed Principle.
This is an image of our high-level component architecture. The Maestro and Calligrapher are responsible for all sound and UI in the game, respectively, and the RiftController manages all Players and Enemies in addition to its own volatility and interactions with them. SpellTarget was a late addition, the parent class of anything (including Objective-related interactables, not pictured) which needed to react to getting hit by Spells. Finally, the DarkMagician was still responsible for facilitating Objective and Room swapping. This is important because of the race nature of the game; each team would always be facing their own unique instance of an Objective, including only the interactables they needed to complete it. Further, each Objective instance needed to be designed to be played independently of, and to not interfere with, the other Objective instance currently in play. When a team completes their current Objective, the next one should load for them, but not affect the other team's Objective (or their ability to complete it) whatsoever. The DarkMagician, my personal masterpiece, was responsible for making all of this happen.
A few weeks into development, I noticed the codebase becoming messier than it should have been so early, and I suggested a Code Jam to help clean it up. The whole team got together for a massive code review, to ensure that it all adhered to our style guide and to make everyone more knowledgeable about the codebase in general. We addressed concerns with performance and extensibility, added verbose comments and updated our release test list, and most importantly, abstracted all the in-game constants into a single reference file. This alone took several hours, but it was well-worth it, saving us future time and hassle because of the work put in here. The standardization also made my job of writing the SDD much easier.
Because of all of our forethought and planning ahead, the development itself went pretty smoothly. Our biggest problems were more "surprises" from the GMAP Team and their advisors. We faced issues throughout the project with art asset integration, because the GMAP Team kept trying out new workflows themselves without letting us know so we could adjust our own accordingly. Midway through the winter quarter, they requested a map rescale, which instantly rendered all of our carefully-curated in-game values for speeds, forces, and spawn locations unusable. Thankfully, the time we had put into the Code Jam saved us here, since all of our constants were in one location and could be quickly adjusted without searching for all of them or their dependencies. Our time could be better spent on testing the new values. The worst headache of the whole project came when the GMAP Team lead decided that the game needed significant, large-scale changes...at the end of winter quarter, when we were supposed to be feature complete and have development all-but done. Needless to say, we were extremely wary of the proposed changes, whether we had time to make them, and whether they were even valid at all. We had several CS Team meetings (including one with our own advisor) to determine the most professional way to proceed. We finally met with the GMAP Team again and were able to reach a compromise, though one that involved us giving up our spring break to get the work done and still be considered feature complete by the start of spring quarter. But it was important to us that we maintain our good work ethic and reputation, so we did what was needed to satisfy our customer and meet our goal.
Dev Progress Slideshow: