2022 Year in Review

Legend is now entering its fourth year of development. It took the first two years to build the foundation. Systems were stood up, then overhauled once, twice, or even three times in some cases. In 2022, rework dropped significantly (evidence that systems were stabilizing and meeting design needs), enabling me to focus on refinement and content in preparation for a public release. The release didn’t happen due to the unplanned Map Generation 2.0 work, but the game is much, much closer to this goal.

UI/UX Improvements

With the focus on getting a playable version out to the public, UI/UX received a lot of attention. 

  • Quick equipment switching. Melee weapons, ranged weapons, ranged weapon ammo, and light sources can be quickly changed using slots next to the hotbar.
  • New inventory screen with separate equipment slots, stats, and inventory items.
  • Visual indicators for the cell the mouse is hovering over and the default action that will be performed by clicking on the cell.
  • Improved inspect panel now displays each tile and entity in the cell and actions that can be performed on those.  
  • Status effect icons shown for player and enemies.
  • Improved Select Class screen.
  • Stamina and magic bars.
  • Added a loading screen.
  • Changed the main font to Merriweather. Not sure if I’ll keep it, but it’s preferable to the low resolution, fixed-width font I was previously using because it’s more compact and looks less retro.
Updated UI
Loading screen
Status effect icons
Select Class screen

Visibility

Using the Smart Lighting 2d Unity asset, dynamic lighting, shadows, ambient lighting, and entity light sources were added. In addition to giving dungeons more ambience, the new lighting creates some interesting gameplay. Players should proceed with caution because who knows what could be lurking in the shadows… Lighting example.

One of the trickier features implemented this year was partial wall hiding. This was needed because walls between rooms occupy a single cell. The player shouldn’t be able to see the wall in the other room. Partial wall hiding solves this problem by only drawing the portion of a wall cell that is visible to the player. Partial wall hiding example.

New Content

The slowdown in systems development, and maturation of those systems, made it possible to create a lot of new content. Dozens of new enemies, items, and objects were added. Abilities were finally added to the game as well.

Examples:

Crystals | Torches | Vampire | Eggs | Resurrect Ability | Mass Fear Ability | Summon Giant Rat Swarm Ability | Destroy Undead Ability | Warding Glyph Ability | Kill Touch and Charm Animals Abilities

Map Generation 2.0

At the beginning of November I realized that my map generator was too limited to achieve the game’s vision and that it needed to be replaced. Map Generation 2.0 had four objectives:

  1. New structuring methodology – layout of walls and floors in rooms, corridors, caverns, and other shapes
  2. Sections – map partitioned into separate areas with discrete structures, themes, and content 
  3. Data-driven stocking – replace the existing hardcoded dungeon stocking with a data-driven implementation
  4. Node pattern-based stocking – identify the best locations on the map to place specific types of content using node patterns on the map graph

All four objectives were completed. Much of the code from original map generation was still usable, but had to be repackaged. Some code, such as the BSP code, was scrapped. The new generator is much cleaner and, most importantly, is capable of producing the kinds of maps I originally envisioned (with some more fine-tuning).

New multi-section map structure and map graph visualization improvements

Unity Assets

I acquired some fantastic Unity assets in 2022:

  • Odin Inspector and Serializer – I can’t recommend this asset enough; it’s a must-have for Unity developers. It can greatly increase your productivity when using the Unity inspector. It’s very easy to learn and start using.
  • History Inspector – super handy. It lists recently viewed assets and allows you to go to those assets with a single mouse click. I was spending a lot of time going back and forth between assets and finding assets before I got this.
  • All in 1 Sprite Shader – I used this to make grayscale and frozen versions of sprites. 
  • 3552 RPG Icons Pixel Art – using for ability icons. I doubt I’ll keep these in the final version because I want all the art to be custom.
  • Pro Sound Collection and Ultimate Sound FX Bundle – added to my stock sound effects collection.

I didn’t end up using:

  • Recently Used Assets – this wasn’t useful because it just tracked assets that changed. History Inspector (see above) is what I was actually looking for.
  • Behavior Designer – this seems like a great tool, but after I bought it I realized I was trying to solve the wrong problem. Legend’s AI meets present requirements, and doesn’t require the sophistication of behavior trees. But, if more complex AI is required in the future I will reconsider this asset.

Ergonomics

I replaced my keyboard with a Logitech MX Keys Mini keyboard and mouse with a Logitech MX Vertical mouse after experiencing pain in my forearms, wrists, and hands. I haven’t had any pain since!

Time Tracking

I wanted to understand how many hours I was working on Legend and what that time was spent doing. In April, I started tracking my time using Clockify.me. Since Clockify integrates with Trello, the tool I use to track my work, the overhead added by time tracking was negligible. 

In 2022, I spent 538 hours working on Legend, averaging 10.3 hours per week. 

Hours per week from April – December

Over half of this time was spent on enhancements (new features, feature improvements). 25% of my time went to testing and bug fixing. While I didn’t track time in prior years, I suspect the refactoring time was much higher in those years compare to the 8.7% in 2022 because I was doing a lot more rework.

Time spent by category

2023 Outlook

I’m confident that more people than me and my kids will play this game in 2023. There’s some work to do to get a public release out, and it will be far from finished (and will very likely still contain the Oryx stock art rather than original art). That work includes:

Improved Dungeon Stocking 

Dungeon stocking using Map Elements is currently done on a per-room basis. I want to add multi-room and multi-level Map Elements to provide more cohesion across levels and the dungeon as a whole. An example is placing a locked door and key in different map locations.

Improved Performance

Playing the game doesn’t feel great currently. It’s clunky and unresponsive at times, especially when there are multiple enemies on the screen. A big issue is the way turns are handled. Actor actions are animated sequentially, so the player has to wait for every other visible actor to move before moving again.

Content Creation

Much more content is needed, primarily objects, Map Elements, and map section types, to ensure that maps are varied enough. Some more enemies and items are needed too.

Balancing

Balancing improved in 2022 but still has a ways to go.

Once these tasks are completed, I’ll distribute the game to a small group of people who are interested in trying out Legend and providing feedback. After incorporating that feedback, I’ll create a Steam page and publish an early access version.

Thanks for reading and Happy New Year everyone!.

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.