Weekly Update – June 4, 2021

This week was mostly consumed by writing unit tests. The goal of completing the detailed feature list for Release 3 was missed.

  • Took a deep dive into unit testing. 20 months into development of Legend, the first unit test was written. This week I wrote about 30 unit tests, with each test performing anywhere from 1 to 10 assertions. The unit test setup fully loads a level first. This is an unconventional way to do unit testing, but is preferable in my case because there are so many interdependencies and most of the bugs occur due to some sequence of prior events (and therefore wouldn’t manifest when testing a class in isolation). The process of creating the unit tests led to some refactoring and a few new methods that will likely only be used for testing purposes, for example getting a count on a private collection. I also discovered some bugs right out of the gate. 
  • Overhauled the message log. One of the planned Release 3 features is a better message log, both from an end-user and a code quality standpoint. Instead of having explicit message log writes throughout the code, game events are raised, and an event handler determines 1) is the player aware of the event and 2) does the player care about the event. When the answer to both of these questions is yes, an event is generated to log a message. The message log UI controller listens for these events and displays new messages in the log. I also wrote a message formatter to determine the appropriate subject and object to display in the message (depending on whether the message refers to the player or another actor or object). For some messages, the message formatter also determines the appropriate verb, for example “am” for first-person, “are” for second-person, and “is” for third-person.
  • Kept using Rider. I’m totally sold on Rider at this point. It took some getting used to, but I’m getting a ton of value out of it now that I’ve gained some proficiency with it. The code recommendations have helped tidy up my code. The refactoring, debugging, testing capabilities have greatly improved my productivity.

I’m 75% through writing the initial set of unit tests. Next week, I’ll finish these and get back to finalizing the detailed feature list for Release 3. 

Roadmap, Scope, Issue Tracking

A while ago I posted a question on Reddit about “Getting to 1.0.” This post was prompted by my own struggles with scope creep and getting further away from “done” rather than closer to it. I wanted to share what I’ve used so far to help keep my project on the rails.

Roadmap / Scope

I found that a mind map was the most intuitive way to visualize the game scope because the scope is like a tree that grows more branches and leaves as features are added. Also, it is a great way to visualize what’s in each release. I assign each feature a number that represents the release in which that feature was added. Below is the current mind map, which includes all the features in Releases 1 and 2 and some of the features planned for Release 3. I’m using XMind to maintain the mind map.

Feature mind map

Next to the mind map is the release roadmap. This defines the overall schedule in terms of the releases. Each release has the following attributes: 

  • Goal: The primary goals of the release.
  • Key Features: The high-level scope of the features added in the release.
  • Target Audience: To whom the release will be available; this is either Developer (me), Private (a small list of invited players), or Public (available to everyone).
  • Completed/ETA: The completion date of completed releases, or the target date for future releases. 

Issue Tracking 

I track issues/tasks in Trello because Trello’s simple and fast. I have experience with more robust issue trackers, such as Jira, but those tools were too heavyweight for my needs.

Issue tracking in Trello

My Trello lists are setup as follows:

  • Release Roadmap: Major milestones to complete the next release. These would be comparable to epics in Agile.  
  • Todo This Week: Tasks I’m currently working on. The goal is to clear this list each week. This list is very dynamic; I start with a set of items at the beginning of the week, and tend to add or move items almost daily.
  • Completed This Week: Tasks that have been completed in the current week. I name this list based on the week’s date range. At the end of the week, I archive the list and create a new one with the dates for the next week.
  • Todo – Bug Fixes, Enhancements, Refactoring, Optimization: These are the complete lists of todo’s, with a separate list for each todo category. I occasionally review these and move items into the Todo This Week list.
  • Ideas: When an idea pops into my head, I put it here. It may never get into the game, but this list ensures I don’t forget about it.

The biggest drawback with Trello has been a lack of analytics – I can’t see the number of issues being completed by week, number of issues by category, burndown charts, etc. So, I may move to a more formal issue tracker in the future. Other than that, using a mind map for defining scope and Trello for issue tracking has worked well so far. 

Weekly Update – May 22, 2021

I’m still focused on testing and bug fixing as I try to wrap up the second release by end of May.

  • Switched from Visual Studio for Mac OS X to JetBrains Rider. I’m forcing myself to give Rider another try after quickly dismissing it the first time I installed it. Rider is highly recommended by some well-respected Unity developers. I didn’t like it at first because I felt that it excessively decorated and annotated the code displayed in the editor. And, some key features I constantly used in VS were missing or worked differently (keyboard mappings, search box, finding usages). But, Rider’s growing on me. Debugging is much better; being able to see the current values of variables inline with the code is awesome. Expensive method calls and heap allocations are highlighted. It’s better integrated with Unity.
  • Optimization. There was a brief but noticeable stutter each time the player moved onto a new cell. I fired up the Unity Profiler and found the cause: on the start of each new turn, every actor checked which other actors it could see. The check was expensive; it involved getting all the cells between the two actors (using the Bresenham line algorithm) and iterating through the cells until reaching the other actor or hitting a cell that blocked line of sight. The performance was terrible because the line method was allocating a new list every time, and the check was being performed many times (O(n2)). Initially I tried using the ArrayPool class to avoid the new list allocations, but it didn’t work well for a few reasons I won’t go into. Then I realized a list wasn’t needed at all; I just needed the last point. I wrote a modified version of the Bresenham line algorithm that started from the origin and stopped when the current cell matched the specified predicate and returned the current cell. I reran the Profiler and the performance was much better, but could still be improved. Having each actor call the “CanSee” method for each other actor was simple to code but very wasteful; most of those checks weren’t needed. I changed the code from checking each actor in the list to checking for actors only in the other cells the actor could see. This made performance worse, because the checks against all the cells were costly, and the map is relatively sparse in terms of actors. I removed that change, and went back to checking the list of actors, but added a new check to determine if an actor is in the viewing range of the other actor before running the line algorithm. This optimization significantly reduced the number of times that the line algorithm ran and greatly improved performance.
  • Created an instant status effect for adding/removing money. It seems a little strange to have an effect for money, but it basically does the same thing the instant healing effect does in that it’s changing an attribute by some amount. This allowed a few hard-coded references to money item types (like gold coins) to be removed.
  • Added the ability for items to cause status effects as soon as they are picked up. This was needed for the money status effect and future instant effects.
  • Fixed the health bar display logic. I kept having issues with when health bars were displayed and hidden. I’d fix one issue and create a new one. After sketching out the logic on paper the solution was obvious. The basic rule is: health bars are only visible when an actor/object is damaged and visible. However, when an actor/object is first damaged, the health bar needs to appear at 100% and animate down to the % of health after being damaged, so the basic rule doesn’t apply. And, when an actor/object dies, the health bar shouldn’t be removed (even though health is at 0%) until the animation finishes and the health bar shows 0%.
  • Peeled some more code off of the GameManager class.
  • Fixed a lot of bugs found during playtesting.

Next week my goal is to complete testing on Release 2. I’ve found and fixed 100+ issues over the past few weeks, but it’s still going to be tight.