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 – December 24, 2022

Multi-section map with associated graph

Map generation robustness was this week’s theme. Code was cleaned up, errors were eliminated, and improvements were made throughout the map generation process.

Next week, I’ll move the Map Elements, which are the objects that stock the dungeon, to a fully data-driven implementation. My goal is to finish the year with a fully working version of Map Generation 2.0, which includes separate map sections, new map structuring, and new map content populating.

Weekly Update – December 2, 2022

Map generation version 2 continued to evolve this week, primarily through incorporation of features from the original map generator. These features include caverns, circular rooms, theme correction, and dungeon stocking.

Example maps:

Example map

    Generator in action:

    Map generation version 2 (work-in-progress)

    Looping didn’t make it in yet. I got hung up on partitioning the map into sections, which ties into how the looping will work.

    The above examples use the version 1 stocking logic, which randomly populates each room using a weighted randomizer based on room type rarity. The need for more intelligent dungeon stocking is what triggered creating a second version of the map generator. As with looping, sections are key. The plan is to partition the map into several sections and apply content based on the section type.

    Also, map graphs got some minor improvements – corridors have been de-emphasized by removing the node labels and making the nodes smaller. This makes it easier to understand the map structure. Here’s an example:

    Sample map graph with de-emphasized corridors

    Next week, I’ll figure out map sectioning and looping.

    Weekly Update – November 25, 2022

    The few hours available this week went to improving map generation. Adding dead-end removal and some rules for connecting corridors to other rooms and corridors has immensely improved map layouts. Here are a couple of examples:

    Map example 1
    Map example 2

    Next week, I’ll add looping to reduce linearity and backtracking, and make some minor refinements such as removing redundant doors.

    Weekly Update – Nobember 18, 2022

    The algorithm for determining available space is fully working. I really struggled with it. I expected needing a few days to complete it but those days turned into weeks. The algorithm design itself was sound; it was the calculations that drove me nuts. Ample debug statements and code comments helped get the job done. Another useful technique for troubleshooting procedural generation issues is to temporarily increase simplicity, predictability, and repeatability. To debug the algorithm, I disabled the random starting point and instead set the starting point to 10, 10 and the initial feature size to 5×5, simplifying the math. By using fixed values, I knew what the expected values were (I didn’t have to calculate these in my head every time because the starting point and feature size changed each run). Using the same fixed values for every run made it easy to tweak the algorithm until the desired result was achieved.

    Here are a few examples employing the new available space algorithm. Note that these aren’t playable maps; they simply demonstrate the algorithm at work.

    Map generation example 1 (3×3 rooms)
    Map generation example 2 (random rooms and corridors)

    Other accomplishments this week:

    • Room and corridor fine-tuning. The ratio of rooms to corridors was adjusted, along with the sizes. In both cases, I compiled data from multiple hand-drawn dungeon maps and calculated min, max, median, and mean values. The median and mean values were similar when I removed extraordinarily large rooms from the data set.
    • Smarter corridors. Corridors now only connect to other corridors and rooms from specific points, based on the orientation and direction of the corridor. This helps corridors connect to other features in a more logical fashion.
    • Level graphs working again and improved. Level graphs required a few modifications to function with the new map partitioner. While I was in the code, I made some improvements. The new partitioner treats both rooms and corridors as graph nodes (previously only rooms were nodes), so I gave room and corridor nodes different shapes and sizes to better distinguish them.

    New automated tests. I rarely use test-driven development, but there were some situations this week where it made sense. The calculation-heavy utility methods for determining available space were easier to develop and test independently rather than when integrated into the full map generator.

    Next week I’ll continue refining the new dungeon layout. The goal of putting out a demo by year-end is almost certainly unattainable at this point due to the unplanned procedural generation work. But, I am taking a lot of time off in December and may be able to pull it off. 

    Weekly Update – November 11, 2022

    I continued working on the new dungeon layout algorithm. I grossly underestimated how long it would take to finish. It’s making me miss BSP.

    The grid logic eats massive amounts of time. It’s just little things like mapping local coordinates to global, making sure I’m adding and subtracting 1’s as needed when working with rectangles, remembering that the y value decreases when going north and increases when going south in the coordinate system but the order is reversed when displayed on screen. My graph paper tablet is indispensable for this type of work. I have ten full pages of sketches of rooms and corridors that I used to work out algorithms, calculations, and measurements. Debugging is time-intensive too. Tracing through the code line-by-line to check values, in conjunction with running the map generation visualizer one step at a time, has been effective.

    The maps are better than last week, but still basic. The generation is much more robust than last week. Except in some rare cases, there’s no more problematic behavior like orphaned connection points and overlapping rooms. I haven’t re-enabled the processors that run after the basic level structure is created, so the map is unpopulated. There aren’t even any doors. Here are some examples of where the level generation stands:

    Next week is all about fine-tuning the generator to improve the map layout. I expect this to be time-consuming because it’s a trial-and-error process.

    Weekly Update – October 14, 2022

    Play-testing at the beginning of the week produced a long list of improvements and bugs to work through. There is no better method for prioritizing work than playing your game (or better yet having others play it too).

    • Finalized the Death Screen. Consisting of a text message and “Try Again” button, the death screen is basic, but will suffice for the demo release. It looks simple but took some effort to hide and disable things – stat meters, status icons, enemy health bars, hotbar, player input.
    Death screen
    • Finalized the Won Game Screen. 
    • Separated actions that entities can perform and actions that can be performed on entities. A few times throughout Legend’s development I’ve unintentionally used an object for multiple purposes. This was the case with the entity ActionTypes collection. Originally this object was used to store the types of actions that can be performed on an entity, e.g. the Drink action for a Fountain, the Open action for a Door. Later, I started using it to also store the actions that an Actor could perform. I’m not sure what I was thinking at the time, but I clearly wasn’t thinking enough, especially considering how simple the solution was – two separate collections.
    • New Map Elements
      • Portal. The Portal appears on the last level. When players step into the portal, they exit the dungeon and win the game.
      • Debris Pile. This replaces the Grass Map Element, which didn’t fit into the dungeon setting. The Debris Pile blocks movement and sight and is destroyed in one hit.
    • Minor improvements
      • Turns remaining added to status effect tooltip.
      • Magic bar is hidden for player classes that don’t use magic.
      • When an actor is healed, the floating text showing the number of HP is now green instead of red.
    • Bug fixes
      • The Inspect Panel doesn’t work. Recent changes broke it.
      • Torch light doesn’t appear when the game starts. When I removed all the starting items from all player classes (many of which were added for testing purposes) and re-added them, I forgot to give each class a torch.
      • Torch light doesn’t disappear when a torch is unequipped. I discovered that the torch game object was being added to the player twice. The torch was being added twice because two different events added torches. Two different events exist because one event is triggered by equipping a torch (needed on level 1, when starting items are automatically equipped) and the other is triggered by setting the quick switch slot (needed on level 2 and after because the torch light has to be re-instantiated and the equip event will not fire because the torch is already equipped). I modified the second event to check for the existence of a torch light game object before instantiating a new one.
      • Inspecting cells with multiple entities of the same type doesn’t work.
      • Finite status effects have one extra turn. I had no idea this was happening; adding the turns remaining to status effect tooltips exposed this.
      • Flames show damage floating text when they burn out.
      • Player is able to open doors that aren’t adjacent.

    Next week will look similar to this week. AI isn’t being properly saved/restored across levels or saved games. This will be a pain to fix but is necessary. There’s some interesting map generation work to do too, though I’ll need to be careful to avoid getting carried away with it.

    Weekly Update – October 7, 2022

    Between unexpected issues at work and a lot of thinking and spreadsheeting rather than coding, it didn’t feel like I got much done this week. My brain is getting fried working out how various numbers will change over the course of a run – HP, damage, damage reduction, stat ratios between no/light/medium/heavy armor, net stats from different equipment combinations (this has especially been a headache; I’m tempted to have a single equipment slot for armor rather than body/head/hands/feet), early vs. late game ratios (to control difficulty), etc. It’s been challenging figuring out where to start because there are so many relationships between stats. My starting point is determining what should be the typical number of hits to kill the player according to their armor category and working backwards from these numbers to determine the stat values. It’s also been helpful to write out different combat scenarios like “how many hits should it take a bandit with a short sword to kill a player wearing light armor.” The model is coming together, but there are still many numbers to plug in. After the model is finished, I’ll create a simple simulator to efficiently test it, and do play testing. 

    Aside from all the fun with spreadsheets, I completed a couple of items on the 2022 goal list: finalizing the Select Class Screen and Passive Abilities.  

    • Updated Select Class Screen. Locked classes are now shown as a silhouette of the sprite, with a lock icon (I’d prefer a padlock but grabbed the closest thing I had, which was from the Oryx sprites). Class attributes are now shown in a grid view with the attribute names.
    Updated Select Class screen
    • Passive Abilities. Passive Abilities were previously 25% completed. They could be assigned to classes in the designer, but didn’t appear on the Abilities Panel, didn’t have sprites, and didn’t have any effect in the game. These items have now been implemented. Passive Abilities are currently only used to dictate the weapons and armor that a class can use. Passive Abilities that provide other types of benefits will be added in the future.
    Passive Abilities
    • Finalized the starting classes. Three classes will be unlocked when the game is installed: Knight, Ranger, and Wizard. Just this week I replaced the Rogue with the Ranger. I wanted the starting classes to be the most straightforward classes to play, representing the core combat styles of melee, ranged, and magic. Additionally, the Rogue’s abilities, and map features to use those abilities, won’t be ready by year-end.
    • Common Ability Group. I decided that all classes should have the Run ability. I added a new ability group called “Common” to contain abilities that are available to all classes. I don’t have any other abilities in mind currently that fit into this category, but I expect there will be some in the future. 
    • Q4 plan. I set goals for the remaining weeks of the year. I don’t usually get this granular with planning, but it is necessary to keep me on track and reach my goal of a playable version by the end of 2022. I’ve set goals by month as well, which are:
      • October: remaining functionality
      • November: remaining content
      • December. testing and polish

    Next week, I must finish the initial progression/balancing model. I also plan to finalize the item, ability, and enemy list for the demo release. I’ll also review all of the systems and identify the major improvements/fixes that are needed for the demo release.

    Weekly Update – September 23, 2022

    I threw away a big chunk of the code that I just wrote last week for Stat Modifiers. I made this decision when it became evident that maintaining a running sum of all Stat Modifiers for each Stat Type wasn’t worth the complexity. I originally chose this approach for efficiency; since the modifiers didn’t change that often, it would be more efficient to precalculate and store the values. In practice, however, the values are used infrequently enough that recalculating them every time doesn’t impact performance. The added complexity, primarily due to having to synchronize the running sums with the individual modifiers, increased the implementation effort and defect risk. In general, it’s preferable to store information in one place only.

    • Improved Inventory Panel. The number of inventory slots has expanded from 24 to 32, the panel has widened, and combat stats are now displayed.
    Inventory with stats
    • Tooltips for stat bars and status effects. Hovering over the Health, Stamina, or Magic bars, or a status effect icon, now displays a tooltip with additional info.
    • Actor Debugging Panel. A new toggleable panel displays detailed info about active actors, including location, vitals, status effects, and AI state. It’s been very useful for squashing AI bugs. This is a developer-only feature; it won’t be available to players.
    Actor debugger
    • Bug fixes.

    Next week starts with closing out AI bugs, followed by validating combat calculations (now that Stat Modifiers are in place) and continuing to add sound effects. Also, I’m going to start on interactions between items and objects, such as scooping water into an empty vial from a fountain. 

    Weekly Update – September 9, 2022

    It was a highly productive week. 100% of my time went into features and fixes that are required for the initial release (not always the case).

    • Status effect icons. Enemy status effect icons now appear above the enemy. Player status effects are now represented as icons as well, located next to the health bar.
    Status effect icons
    • Loading screen. New levels now display a loading screen, complete with a progress bar and text describing what is currently happening. At first, the progress bar was based on AsyncOperation.progress, which tracks the progress of an asynchronous scene load in Unity. The bar quickly got to 90% and then hung for around ten seconds. This delay was, of course, the procedural generation. Luckily, when I made the map generation visualizer last year, I had to reduce map generation into hierarchical, independent units of work – maps are generated by a series of processors, processors are composed of stages, stages are composed of substages, and substages are composed of tasks. The tasks are pre-generated and placed in a queue. This enables the map generation visualizer to display the result of one task at a time and interactively fast forward through substages, stages, and processors. It also makes it easy to calculate the progress percentage. I only had to make a slight modification to make it work with the loading screen progress bar, which was to wrap it in a coroutine and have it yield after each substage so that the UI could update the status.
    Loading screen
    • Cell selection improvements. The area of effect is now highlighted and the cell indicator (not just the mouse cursor) is now shown.
    • 15 sound effects added.
    • Bug fixes.

    Next week I’ll take a break from new features to shorten the bug list. Saving and loading is broken again.