Weekly Update – February 27, 2022

The UI work I started last week and planned to finish this week ended up being more difficult than I expected. In particular, the selected cell action indicator (described below) required more coding and some refactoring.

  • Separated equipment slots from inventory. One of the many things I did to get a working game early on was to display equipment slots in the same grid as the inventory slots. In addition to simplifying development, I did this because I hadn’t determined what the final equipment slots would be. After deciding on the equipment slots, I needed to move the slots out of the inventory grid and into their own area on the screen. Equipment is now displayed in two columns, one for main worn equipment (helm, armor, etc.) and another for accessories (necklace, ring, etc.), with an image of the player sprite in the middle. Note the sprite does not yet reflect the actual items equipped by the player.
Separated equipment and inventory
  • Selected cell indicator. The cell that the mouse is hovering over is now indicated by a camera frame icon. This makes it easier to tell which cell is selected when the mouse cursor is in between two cells.
Select cell indicator
  • Selected cell action indicator. In addition to displaying the selected cell indicator, hovering over a cell now displays an icon indicating the action that will be performed when left-clicking on the cell. This is useful because the action the player performs when clicking on a cell depends on several factors: the contents of the cell, the player’s proximity to the cell, and the player’s selected melee and ranged weapons. For example, the icon shown over a cell that contains an enemy and is adjacent to the player will display a melee attack icon. Non-combat actions can be displayed, such as opening a chest.
  • Moved game menu buttons from the bottom right corner of the screen to the middle right side of the screen. This was done to better balance the UI layout, specifically by making the quick switch slots and menu buttons symmetrical.
  • New Map Element: Lairs. Lairs contain a dangerous beast and are littered with bones. They’re generally found in dead ends in caves.
Lair Map Element

Next week, I’m confident I can close out the remaining UI work. This was my main goal for February, so I’m a tad behind.

Weekly Update – February 11, 2022

UI finalization, which started two weeks ago, continued this week. Some questions that have been open since day one, such as available equipment slots, are getting answered because they’re dependencies for completing the UI.

  • Decided on equipment slots. This is finally done. It was one of those things that I overthought. My original philosophy was to keep things simple and have a single armor slot, and some slots for accessories like rings. My thinking changed as the depth of the game expanded. The final equipment slots are Armor, Helm, Gloves, Boots, Necklace, Rings (2), and Shield (note that weapons are handled in a different manner, to be explained in a future post). Adding the new slots to the actor inventory was easy. I had to do a little bit of rework because of the rings. The original logic assumed that there’d only be one slot per equipment type.
Equipment slots and new items
  • Updated damage absorption and evasion calculations. With multiple pieces of equipment potentially affecting damage absorption and evasion, I had to update the combat calculations. This wasn’t difficult, but balancing got more complicated. I now have to consider mixed pieces of equipment, partial equipment, and class restrictions on each equipment type.
  • New items: Leather Gloves, Leather Boots, Leather Cap, Wooden Round Shield, Wand of Magic Missile, Necklace of Protection, Ring of Invisibility. These were created to test the new equipment slots. They may or may not make it into the final game. In particular, the Ring of Invisibility, which grants invisibility as long as it’s worn, is too overpowered.
  • New map elements: Mushrooms and Crystals. Caves are in need of more variety so I added glowing mushrooms and crystals.
Crystals
  • Indefinite status effects. Previously all status effects were temporary; after a certain number of turns the effect disappeared. Now, status effects can last indefinitely. This was needed for the Ring of Invisibility and will be needed for all equipment that gives the player a status effect while worn. 

Next week, I’m implementing the quick switch slots for weapons and light sources as part of the UI finalization.

Weekly Update – February 4, 2022

It was one of those weeks where most of the time went into thinking rather than doing. Hence, there weren’t many concrete achievements. The thinking was around UI design, specifically how to quickly switch between different weapons, how to automatically use ranged weapons for distant enemies and melee weapons for nearby enemies, how to handle torches, and equipment slots. I wrote out so many different solutions. None of them were perfect; they each had pros and cons. I think I’ve chosen a solution but need to consider how the solution applies to all the possible scenarios. The solution involves an additional hotbar that lets the player quickly change melee weapons, ranged weapons, and ranged weapon ammo, and logic for when the player clicks on a cell that determines whether to use a melee or ranged weapon. It seems sound to me, but only feedback from other players will confirm whether it is intuitive and user-friendly.

I added a few new map elements, which is something I’m trying to do every week to have a wide variety by launch. As always, there were some bug fixes too.

  • Witch’s Chamber. The Witch’s Chamber map element places a cauldron, a witch, and some bookcases and tables in a room. The witch is brewing something in her cauldron, which emits a blue glow. I need to give the witch some abilities. I’m not sure what I’ll do with the cauldron.
Witch’s chamber
  • Summoning Chamber. The Summoning Chamber map element places a summoning circle, demon, and summoner in a room. The summoner has just recently summoned a powerful demon in the summoning circle. I need to build out the demon’s abilities and the summoner’s AI (the summoner lets the demon do the fighting and avoids the player).
Summoning chamber

Also, here are a few examples of the objects added last week:

Pots and varied rubble
A rug
Grass and statues

Next week I’ll implement the UI features I spent this week designing and try them out in the game. This is the next item on the critical path. 

Weekly Update – January 21, 2022

Two big features were completed this week: lighting and partial wall hiding. Both of these features affect what the player sees to produce a more authentic dungeon crawling experience. Finishing them feels great; they required a lot of brain power! 

  • Lighting (v0.95). Lighting now works as desired, mostly. With the ambient lighting, shadows, and illumination, the maps feel a lot more like dark and foreboding dungeons. It may be too much; I’m still tweaking brightness, colors, and distances to get the right balance of visibility. Also, the frame rate has taken a hit, so I will need to improve performance.
Lighting
  • Added partial wall hiding. Now, the portions of walls that the player can’t see, for example the other side of a wall shared by two rooms, are hidden. This prevents players from knowing what’s on the other side of a wall. It also solves the problem of secret doors being too easy to spot.
Partial wall hiding
  • New test console features. Entities can be spawned in specific locations now (previously they spawned in a random cell adjacent to the player). Extended logging can now be enabled/disabled from the console. These features were added to speed up testing. I’m often using the console to spawn health potions – I need to have more of those drop in the game and/or do some more balancing.
  • Map generation bug fixes. Some objects, such as braziers, were being added under walls or next to doors.
  • Time-consuming animation bug fix. Occasionally, the player’s character would stop responding to player input and effectively bring the game to a halt. I used a new test console feature to view the game turn state and found that the game was stuck on an enemy actor’s turn. I added some breakpoints and found a clue: the actor’s state was stuck in attacking; the actor never received the event that’s fired when an attack animation finishes. That made some sense, because the attack animation wasn’t playing in the first place. I thought maybe it had to do with how I had configured the animation controller and transitions in Unity, or perhaps it was periodically skipping animation frames that fired events. There are plenty of reports of these types of issues in the Unity forums. Those turned out to be red herrings, though it took hours to realize that. The real cause was some code I recently introduced (mistake #1 – not reviewing recent code changes) that enable/disabled animations based on whether the actor could be seen by the player. I only added this functionality when the player moved to a new cell, but not when an actor moved to a new cell. So, if an actor moved from a cell the player couldn’t see to a cell that the player could see, the animator component was still disabled and the animation didn’t play. I solved this by moving the enable/disable logic into the actor visibility property (mistake #2 – implementing logic at too high of a level in the code instead of where the property changes).

Next week, I’m fine-tuning lighting and making some UI improvements. Now that there’s a lighting system, I want to add some more light sources like luminescent fungi and crystals, if I have time.

2021 Year in Review

2021 Retrospective

Legend has been in development for 2.3 years. It’s hard to believe that that much time has passed since I started working on the game. I don’t know if anyone else has experienced this, but how I felt at the two-year mark was in stark contrast to my feelings at the one-year mark. After the first year of development, I was thrilled with how much I had accomplished and excited for the future. At two years, panic set in. How could I possibly finish at the rate I was going? Was I wasting my time? Was this game even any good? 

Ultimately, the mid-gamedev crisis was a good thing. This was my brain telling me to reassess and correct course. That’s exactly what I did in the latter part of the year. The reality was that, at the rate Legend was progressing, it would need at least several more years to release. I don’t want to wait that long (I have more games to do!). I cut a large chunk of planned features while preserving the original vision. I forced myself to make decisions. I have a tendency to postpone decisions as long as possible to avoid limiting possibilities. It’s been a sure-fire way of keeping completion in the distant future.

Development thus far has consisted primarily of building the game system framework, and rebuilding many facets of the framework as my Unity knowledge increased and my ideas crystalized. Heading into 2022, the framework is done and development shifts to using the framework to flesh out the actual game.

What I said I was going to do in 2021:

Replacing the stock art

Completion: 0%

I’m still using Oryx. I still have some uncertainty about the exact 2D perspective that will be used. I also feel that the art doesn’t need to be replaced until the game is ready for a public release.

More content 

Completion: 5%

A handful of new enemies, items, and objects were added. Every piece of existing content was reworked in some way, for example extracting a parent class for actors and items, and moving from room-based to element-based map generation.

More polish

Completion: 30%

At the beginning of 2021, I never would have expected to accomplish as much as I did in this area. I considered polish something you do at the end of development. That largely is the case, but I’m using “polish” loosely here to refer to any visual and audio effects beyond the bare minimum, and refinement of any sort, such as fine tuning procedural generation and balancing combat. The game looked bad and felt dull whenever I did testing. Even though I knew I’d improve the look and feel before launch, I was still getting discouraged. For my own psychological benefit more than anything else, I added some game juice, including:

  • Particle effects
  • Better combat and movement animations 
  • Screen shake
  • Environmental impact: corpses, particle effect residue
  • Sound effects

Visuals | Sound Effects

This did the trick; I could finally envision other people playing the game.

Community building

Completion: 5%

I posted a weekly dev update on the website and Sharing Saturday on r/roguelikedev. I posted the link to each Sharing Saturday update on Twitter. I occasionally posted videos on Youtube. I have tiny followings on those channels. I continued to spend a minimal amount of time on community in favor of game development.

Early access release (aspirational goal)

Completion: 10%

This was nowhere close to happening, but there was movement toward this goal due to focusing on it at the end of the year. I also created a mind map visualizing features by release and a roadmap.

What else happened in 2021:

The new map generator, started in 2020, was finished in January. I built some dev tools for procedural generation analysis, tuning, and troubleshooting: an interactive map generation visualizer and a map graph visualizer. These proved to be very handy.

A map graph

I made another major change to map generation later in the year with the addition of Map Elements. These are the basic building blocks for populating a map with content after the map structure’s been created. They’re hierarchical and modular, enabling rooms to be constructed from layers of interchangeable components and reuse common components. For example, many room types can include an Abandoned Map Element that adds cobwebs and debris to give the appearance that the room is abandoned.

Maps became both more varied and more playable. Map configuration parameters, which dictate a map’s structure (number of rooms, room sizes, room distances, room themes, etc.) are now randomized. This additional layer of procedural generation increased the variety of maps while maintaining consistency within a map. Map configuration parameter ranges were fine-tuned to avoid problematic maps. Room type probability changed from a linear distribution to a weighted distribution based on rarity to give maps a more logical composition of rooms.

Significant UI work was done. New screens were added, a hotbar was added, and the main game UI was refined. 

Class selection screen
Inventory and hotbar

In action:

AI was expanded. Now, actors can have their own AI controllers and behave differently than other actors. AI controllers can be reused across multiple actor types. Actors can now track any number of other actors, enabling them to do much more than charging the player. They can attack, defend, and interact in other ways with tracked actors as dictated by their AI controller. Actors now gain awareness of events based on their vision and hearing ranges and act based on the type of event occurring. Each actor has its own inventory and the ability to pick up items and use them. When an actor dies, other actors can acquire the items it was carrying.

In light of my time constraints and the mountain of work remaining, I made a deliberate effort throughout the year to increase my productivity. The ways in which I did this include:

  • Reducing and simplifying code.
  • Moving logic from code to configuration (physical material interactions, game events).
  • Adding unit testing.
  • Adding an in-game console for spawning objects to accelerate playtesting. 
  • Adding more granular logging so that I have more information to troubleshoot.
  • Consolidating test settings into a single design-time editable object.
  • Switching my IDE from Visual Studio to Rider.
  • Reorganizing my Unity editor layout.
Reorganized Unity Editor layout

Finally, code rework occurred throughout the year. Most of it was necessary to keep the code maintainable, but I also know that I am overly eager to rework code and sometimes create more problems for myself than I solve. As the year progressed, the rework did slow down. There are two reasons for this: 1) the framework reached maturity and 2) I became more selective with when I reworked code. Before I make changes or add new features, I now consider what compromises I can make and what I can do within the existing framework to avoid rework. 

2022 Outlook

This year’s goals are essentially the same as last year’s. However, the priorities have changed. An early access release is now the primary goal. Original art, a requirement for the release, is also a top priority. Effort will be concentrated on what is absolutely necessary for public release, including tightening the game loop, balancing, and clearing the bug list. 

Weekly Update – December 24, 2021

Happy Holidays everyone! With a few days off from work this week, I got a lot done! Many of the changes were visual, which always feels more productive. I primarily worked on combat game juice.

Combat game juice
  • Corpses. Slain enemies now leave corpses behind. This increases the player’s impact on the environment and will be used for a variety of mechanics including reanimating corpses, enemies reacting to corpses, and combat modifiers when fighting on a cell containing a corpse. I was pleasantly surprised to find that this feature didn’t require any code changes. It was implemented entirely in the Unity Editor using the custom trigger/effect framework developed earlier in this year.
  • Particle effect residue. Particle effects can now leave permanent residue, such as blood stains and bone fragments. Along with corpses, this is intended to increase the player’s feeling of leaving a mark on the environment. You can very clearly tell where battles took place and the size of those battles.
  • New walk and attack animations. After getting frustrated a couple of weeks ago by not being able to make a decent walk animation, I took some time to learn more about classic animation techniques. I applied the squash and stretch technique to walk and attack animations. I also added a slight pause to the beginning of attacks for anticipation. I got much better results this time around, due primarily to a more precise application of squash and stretch.
  • Replaced animation implementation. In researching Unity animation techniques I discovered Unity’s new 2D Animation package. This package provides a way to reuse animations with different sprites. Previously, I was using what I believe is the traditional methodology – for each animated game object prefab, create an animation override controller for the animation state machine, duplicate the animations referenced in the animation controller, and replace the sprites in the animations. This technique has major drawbacks: 1) it’s tedious 2) it generates a lot of redundancy. If I ever needed to change a common animation such as walking, I’d have to change every copy of the animation. The 2D Animation package provides a way to define an animation only once and swap out sprites based on the game object using the animation. This is done by adding a sprite library and sprite resolver component to each animated actor and configuring animations to reference the spriter renderer properties rather than the sprite directly.
  • Added a parent to all animated actor prefabs. This was suggested by /u/Notnasiul as a way to use relative positioning in animations and as a general good practice. It took around an hour to go through the existing actor prefabs, add a parent game object, and move the Sprite Renderer component to a child game object. And… it worked great!
  • Directional attack animations. With the capability to control relative game object position in the Unity animator, and trigger events in animations, I was able to remove the code that was previously responsible for this. This code was complicated. It updated the game object position on each Update() based on an easing function and managed time-based state changes for different points in the animation where events had to occur. I was glad to see it go.
  • Reconfigured my Unity Editor layout. Up until now I’ve been using the default Unity layout. This layout has been workable but not optimal. The project asset hierarchy panel isn’t large enough, the game object hierarchy panel is too large, and some tabs that need to be viewed concurrently (such as Animation and Scene) are by default in the same panel. I reorganized the panels to better suit the needs of this project. This is the end result.

Next week’s goal is to give level 1 the right amount of challenge. To do this, I’m going to tweak stats and drop frequencies for items and enemies. I want to finish the year with at least one good level. 🙂

Weekly Update – September 24, 2021

I continued to work on combat this week, but shifted from core mechanics to “game feel.” After adding particle effects and sound effects, combat is much more satisfying. The game is getting closer to being fun. 🙂 

New Videos

Combat particle and sound effects

New GIFs

Blood splatter
Bone spray
Stone spray

This Week’s Achievements

  • Combat particle effects. I’ve never worked with particle effects. There’s a learning curve with Unity’s particle effects system, but being able to change settings in the editor and see the effect in real-time helped immensely. Also, I accelerated by learning my buying a particle effect package in the Unity asset store and studying how it worked. I created a few particle effects for when an actor/object is hit with a weapon. The target’s physical material determines the particle effect. For example, when a rat is hit it will spray blood, while a skeleton archer will spray bones and bone fragments. Additionally, the size and number of particles vary based on the amount of damage inflicted.
  • Improved combat sound effects. I was annoyed with the combat sound effects I chose. They were so quiet and boring. I was going to have to either find better assets, increase the volumes of the assets I had, or use the Unity audio mixer to get better sound. I was also running into an issue where the direction the sound was coming from was wrong. But, that issue ended up being a blessing in disguise because it made me realize why I was having low volume issues: the audio listener was attached to the main camera, which was way up above the player. When I attached the listener to the player, all the volume issues went away (though I haven’t fixed the directional issue yet).
  • Added hooks for additional sound effects, including dying, taking an object, ambient sound, footsteps, and walking on different types of terrain. Footsteps are challenging. I lowered the volume and slightly randomized the pitch of each step to make them less prominent and repetitive.
  • Right-clicking does something. Right-clicking on an object will display the Inspect Panel for that object. I should’ve done this a long time ago, but it was overlooked because the original target platform was mobile rather than PC.
  • Mapping the number keys to hotbar slots. Another basic feature I overlooked – allowing items in the hotbar to be used by pressing the corresponding number key.
  • Added probabilities to triggered game events. For example, when a pile of bones is destroyed, there’s a 50% chance that a ghost will spawn. This provides some unpredictability and more player choice.
  • Framework for player notifications in the Inspect Panel. When a player inspects an object, in addition to the description of the object, I want to communicate important gameplay information. For example, if the player inspects an object that is far away, I want to inform players that they need to be standing next to the object to interact with it. There’s now a framework for collecting notifications from various sources and prominently displaying them on the Inspect Panel.
  • Fixed many combat bugs. There were a surprising number of things that didn’t work or caused crashes. The majority of these bugs were from the last major refactoring.

Next Week’s Goals

Next week, I’ll continue working on “game feel” and small refinements that go a long way. I’m way off track on the milestone schedule, but I feel closer to being done than I think I would have had I stuck with the planned milestones. The additional content I was previously working on wasn’t making the game any better because the core loop was lacking.

Weekly Update – July 23, 2021

Two Release 3 features completed this week: Class Selection Screen and Continue Game Screen.

Select Class Screen
Continue Game Screen
Title, Class, and Continue Screen Video

Only three classes will be available when the game is installed. Additional classes can be unlocked for a total of 16. I haven’t determined how the additional classes will be unlocked yet. 

An unlimited number of games can be saved and resumed at a later time. Games are saved automatically when a new game is started and on application exit. A saved game is deleted when it is loaded to prevent save scumming.

Aside from new features, I did some more cleanup from the big actor refactoring two weeks ago.

Next week, I’m starting on the hotbar and doing a lot of design work on spells and abilities.

Weekly Update – June 25, 2021

  • I stuck to the plan this week (for a change) and finalized the Release 3 features. I’ll publish a summary in next week’s post.
  • Added cell-based status effects. These are effects that are added when an actor moves onto a cell and removed when an actor leaves a cell. An example is a Darkness effect that limits the player’s visibility. This builds on the existing capability to add status effects by using an item or interacting with an object. This feature was unexpectedly difficult to add; a lot of the status effect code and Unity configuration needed to be reworked.
Darkness cell effect
  • Room features. Each room has a room type that determines what’s in the room. For example, a Shop Room contains a shop and a Treasure Room contains treasure. I needed to be able to apply different features to a room to do things like placing a trap inside of a treasure room. I added a base RoomFeature class and some child classes like ShopRoomFeature and TrapRoomFeature. This makes it possible to mix and match different features can create a wider variety of rooms than was possible using room types. I still need to fully incorporate this into the map generator, specifically by replacing the existing room generation with feature-based generation.
  • Overhauled effect triggering. I was never comfortable with the way I originally implemented the configuration of status effects caused by an object or item. Effects inherited from MonoBehaviour so that they could be added to game objects in the Unity editor. It worked, and it was designer-friendly, but it was unintuitive (it wasn’t obvious the purpose of the component was to cause an effect) and too heavyweight (multiple effects required multiple components). I converted effect types to ScriptableObjects and created a new class containing a list of effect types. I called this class TriggeredEffectCollection and used it to replace the individual effect components. Adding effects is now easier (add/remove from a list editor in the Unity inspector) and the purpose of the component is more clear.
  • Removed the limit of one static object per cell. Now cells can have any number of static (not moving) and dynamic (moving) actors/objects. For example, a cell can now have a floor trap and a statue. This also simplified the code because now there’s just a list of actors/objects instead of a list plus the static object.
  • Extensive actor AI logging. Now the log very clearly shows why an actor chose a particular action and not others. Very handy for troubleshooting. The basic AI process is to 1) identify the potential actions and 2) select the best action. The logging explicitly indicates why potential actions were available or unavailable, and why potential actions were rejected or selected.
  • Added new effects: Cure Poison, Darkness, and Paralysis.
  • Added new items: Cure Poison Potion, Throwing Axe.
  • Damage type resistance. Physical materials now have explicit resistances to different damage types. This will be used to do things like making an axe more effective against a wooden door than a short sword.

The plan for next week is to replace Room Type-based room generation with Room Feature-based room generation and start on two new features: Enemy Alerts and Knowledge. The former provides visual indicators for whether enemies have seen the player and the former varies the descriptions of things based on the player’s knowledge.

Weekly Update – May 7, 2021

I continued firming up Release 2 this week. 

  • Improved cell highlighting. When selecting a target cell to shoot at or throw an object at, highlighting now excludes cells that can’t be seen
Highlighting cells for shooting
  • Improved actor tracking. Enemy and NPC AI controllers were hardcoded to track the player. This caused a bug where other actors weren’t tracking the player because they were being instantiated during map generation, before the player was instantiated. But, the real problems were that a) the AI should determine what is being tracked instead of hardcoding it and b) the decision to track should be made when the other actor becomes visible, not when the tracking actor is created. I removed the hardcoding, extended the AI to determine what an actor tracks, and moved adding tracked actors to the point when the tracking actor sees the actor to be tracked.
  • Improved health bar visibility logic. Health bars used to appear over every damageable, dynamic actor. Now they only appear when an actor has been damaged, and appear for static actors like doors.
Health bars now only appear when actor/object is damaged
  • Miscellaneous refactoring and code improvement, which includes:
    • Changing variables from public to private
    • Removing unused classes and code
    • Consolidating redundant code
    • Method comments
  • Many bug fixes. When things break, I’m spending more time on the fixes to lower the chance of the same things breaking in the future. I’m making progress but I have a lot of room for improvement.
  • Trimmed scope. I moved some planned enhancements from Release 2 to Release 3. I’ve been working on Release 2 for 15 months. That’s a lot longer than I want to spend on each release, so I pushed out the remaining planned enhancements to the next release.

Next week, play testing and bug fixing continues as I work toward wrapping up Release 2.