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. 

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.