Adding a new ability to summon a swarm of giant rats nearly derailed my plans for this week (and potentially the next few months) when I tried out the ability and, to my surprise, the rats started attacking each other. I realized that there was no way of indicating that the rats were both allies of the player and each other; I needed to be able to specify relationships between actors. Factions were the first thing that came to my mind. They’re overkill for this single use case, but I’ve always intended to have factions in the game and reasoned that I could use them to solve the rat problem. As I’ve done with other aspects of the game design, I start with a flurry of research and brainstorming. I read up on factions in game design and roguelikes specifically, including a FAQ Friday on the topic, and wrote down all of the ideas and details I could think of. And, as I always do in this situation, I got lost in the subject and created a conceptual design that far exceeded what I likely needed and what I had time to build. That’s not a bad thing, as long as you can quickly pull yourself back into reality and reduce a grandiose design to something practical. I was able to do that in this case. My solution was to add an actor attribute indicating whether the actor is friendly, neutral, or hostile to the player. It’s a compromise, and there’s a good chance it will be thrown away in the future when I add a true faction system, but it’s the right solution right now, because it was extremely simple to implement and I don’t have a clear vision for how factions will work.
New Ability: Summon Giant Rat Swarm. Summons a swarm of giant rats to fight on the player’s behalf.
New Item: Fire Sword. Sets enemies and objects it strikes on fire. It’s overpowered at the moment, but I haven’t decided how to nerf it.
Chests and corpse item access. The items contained in chests and corpses can now be viewed and taken from the Inspect Panel. A “Take All” button lets all items in the container be taken at once.
Inventory Panel is automatically displayed when inspecting a container. When viewing a container, such as a chest, the player inventory is now displayed automatically. This allows items to be dragged from the container into inventory and vice versa.
Weighted observation selection. One of the configurable AI components is the ObservationDecider. This component examines the actor’s observations since the last turn and chooses an observation to react to. There are two implementations of this component, one that selects the first observation involving a tracked actor, and another that randomly selects an observation (used by the Fear status effect). These implementations are primitive. They don’t work well when there’s more than one suitable observation to respond to. To address this, I modified the ObservationDeciders to weight each observation and select the highest weighted observation.
New automated tests: Eggs. I’ve repeatedly broken the functionality of eggs, so this was a great automated test to add. The unique behavior of eggs (turning into a cracked egg upon detecting the player, waiting 10 turns to hatch, hatching a creature at the end of waiting) tests a number of systems.
Installed History Inspector from the Unity Asset store. My project asset list has gotten enormous. ScriptableObjects are used extensively, and many of these ScriptableObjects reference other ScriptableObjects. I often have to follow a trail of ScriptableObject references to fully understand how something is working, or go back to the previous asset I was viewing. The time spent scrolling through the asset tree, and the effect of navigating the structure on cognitive load, is impacting my productivity. I looked for a built-in Inspector history viewer in Unity but couldn’t find one. So, I turned to the Unity Asset Store and found the History Inspector asset. It’s already become an indispensable tool that’s saving me a lot of time.
Next week, I’m play-testing combat and overall level difficulty. I’ll adjust and fix based on what I find. The overarching goal for the year remains getting to a version of the game that I can distribute to others.
Resurrection ability particle effects. I mentioned last week that implementing Resurrection was simple. However, this week I hit a snag when I tried adding particle effects. The particle effects were triggered to start at the same time that the Resurrection effect itself started. This didn’t look right because the corpse would change to a living actor just as the particle effects were starting. I added a new Action Step for particle effects so that the particle effects could run in parallel with the Effect Action Step. Then I added a delay parameter to the Effect Action Step so that it could start half a second after the particle effects started. Now the actor appears to come back to life half-way through the particle effect emission and looks much better.
AI fixes. I fixed some problems that were rooted in my losing track of what the ActorTracker class is supposed to do. Actors are designed to only act when they need to, which is typically when they see another actor that they’re interested in. This is done for efficiency; the game would be too slow if every actor in the level acted on every turn. The ActorTracker class was created to allow an actor to continue acting after it can no longer see any actors that it’s interested in, enabling the actor to pursue another actor temporarily. At some point, I started using this class to permanently track actors that an actor was interested in, and built logic on top of this new use case. When the player’s actor was instantiated, every enemy in the level added the player to its ActorTracker. That caused every enemy to check if it could see the player at the start of each turn. This is an expensive check when the player is in the enemy’s sight range, because line of sight is used to confirm that the enemy can see the player. Aside from the performance issues, the shift in how ActorTracker was used broke AI. And, ironically, pursuing actors that were no longer visible, which was the original purpose of ActorTracker, didn’t even work anymore. To solve these problems, I went to my best tools for walking through complicated flows: graph paper and a pen. I diagrammed the AI steps, located the logic flaws, and fixed them in the code. I scaled ActorTracker back to its original purpose and added comments to help me remember its scope in the future.
Chest and corpse user experience design. One of the oldest items on my todo list is getting chests fully working. This has been held up by incomplete design. Until this week, I hadn’t determined how the player would interact with chests, and how that would translate to the user interface. I’ve been putting off making that determination until I played some other roguelikes and CRPG’s to get a sense of how other games handled this. Downloading, installing, and playing multiple games until I found a chest seemed too time-consuming, so I resorted to watching a bunch of Youtube videos to find examples. The latter was much more efficient.
Next week, I’ll get chests fully working and fix bugs along the way.
Implementing the Vampire’s AI was a lot of work. The process revealed the need for additional capabilities to support more varied and advanced AI. With the new AI framework, creating AI for new enemies in the future will be faster. The Egg, also added this week, is evidence of that.
Vampire. The Vampire is a dangerous enemy that has the special ability to transform into a bat and flee when its health is low. It returns to Vampire form after its health regenerates.
Egg. When the Egg detects the player nearby, it starts to hatch. The Egg can be destroyed in one hit if the player gets to it in time. But, if the player doesn’t get to it in time, a creature hatches from it.
Coffin. A Coffin can be opened or closed and can contain a Vampire and/or items, or be empty.
Puddle. This is a single cell containing shallow water. It’s only found in caves. It’s just decorative at the moment. I plan to leverage the existing Physical Materials framework to add interactivity.
New Map Elements
Coffin Area. This map element places a single Coffin in a significant location in a room.
Egg Area. The Egg Area Map Element contains a cluster of Eggs.
Built new reusable capabilities. The above features required the implementation of new capabilities including a new action type to move an actor and trigger an effect at the same time (used when the Vampire flees to move away from the player and transform into a bat), a health regeneration status effect (used by the Vampire), the ability to prevent health bars from animating in specific situations (used when a Vampire transforms into a bat and health is transferred), generate particle effects when effect types are triggered (used to display a cloud of smoke when the Vampire transforms), and a new AI for actors that triggers an effect when the player is seen (used by the Egg to transform into a Cracked Egg), with an optional delay (used by the Cracked Egg to hatch after a number of turns).
`Next week will be a mix of new content and bug fixing.
I’ve noticed that for at least several weeks, my todo list hasn’t gotten any shorter. I’m adding as many items to the list as I’m removing. The scope of the remaining UI work keeps growing, either because tasks are taking longer than expected or the features that have been added require additional features. It’s been time well spent, however; the UI is critical because one of my key goals is make the game as easy to learn and play as possible.
Added text to Action icons. UI best practice is generally to display labels with icons rather than icons alone.
Inspect Panel improvements.
When inspecting a cell, the Inspect Panel now displays all inspectable objects in the cell, including actors, items, and the cell type itself. This allows the player to see details and perform actions on a specific inspectable in the cell (previously only the top inspectable was accessible).
Actions that can be performed on the object being inspected but aren’t available for some reason (typically the player isn’t close enough to the object) are now displayed so that the player can see all potential actions.
Tooltips for empty hotbar, Quick Switch, and Quick Switch Deselect slots. Hovering over one of these slots now displays a tooltip indicating what the slot does and how to use it.
Actions that can be performed on an item or actor are defined as lists that can be edited in the Unity editor. This worked well until I created a new action that applies to all items. Since most items have the same actions, I created a ScriptableObject called ActionCollection that contains a list of actions and replaced the entity action list with a list of ActionCollections. This allows changes to be made quickly to the core set of items, enemies, or other related entities, while still allowing for variation.
Actors in a cell are stored in a typed list. Likewise, items are stored in a separate typed list. This was implemented before I modified actors and items to inherit from the same parent, Entity. Having two separate lists caused some problems. One of those problems was that the order of an actor relative to an item couldn’t be determined. The logic that occurred when a player clicked on a cell checked actors first and items second. So, if a cell contained a table and there was a health potion on the table, clicking the cell caused the player to hit the table rather than take the potion. I solved this problem by combining the actor and item collections into a single entity collection. This was easy to do because the interface remained the same.
The recent rework made it possible to use a data-driven for some actions that were previously hard-coded. For example, each item now has a Take action, replacing logic that automatically performed a take action if an entity was an item.
Started tracking my time with Clockify.me. It integrates with Trello, the tool I use for planning and issue tracking. I’ve started tracking my time to become more aware of how much time I’m spending on the project and where the time is going (enhancements, bugs, etc.).
Thought more about a new name. I came up with one name that I like and a short list of decent names. This process is going to take a few weeks at least.
Next week will likely consist of more UI refinements.
Cell Context Menus were the top priority this week, but most of my time went to implementing torches. I had a rough time getting lighting and extinguishing torches working. The implementation is probably overengineered; it provides more flexibility than I’ll likely ever need and, consequently, has a high complexity cost. It’s also on the messy side – multiple SOLID principles are violated. After writing the code, it took several hours to figure out why it wasn’t working because the sequence of events in the code was difficult to follow. I just got it working today, which held up my weekly update.
Item light sources. Items can now add light sources to actors. This capability was needed to support torches and other light source items. It will also be used to radiate light from certain magic items.
Torches. Torches now work properly. When the player selects a torch in the Light Quick Switch Slot, the torch will automatically light and illuminate the area around the player. Deselecting the torch will remove the illumination and extinguish the torch.
Moved game buttons to the right of the hotbar. Originally the game buttons were in the lower right corner of the screen. I later relocated them to the right middle area. Now, they’re back at the bottom of the screen, but next to the hotbar. I did this to get them out of the way of the Inspect Panel’s new location.
Moved Quick Switch Slots to the left of the hotbar. These were originally on the left side of the screen, mirroring the game buttons. To maintain symmetry with the game buttons, and consolidate buttons and slots, the Quick Switch Slots were moved to the left of the hotbar.
Quick Switch Bar improvements. The currently selected item was being shown twice, once in the Quick Switch Slot, and once in the Quick Switch Bar. This was confusing and redundant. Now the selected item is excluded from the Quick Switch Bar.
World building. Although the dungeon is procedurally generated each game, the world in which the dungeon exists is fixed. Each generated dungeon will reference some world events, historical figures, peoples, places, deities, etc. Gradually, the player will learn more about the world, which will make the references more meaningful and factor into gameplay. This week, I started fleshing out this world.
Cell Context Menus didn’t get enough attention to warrant a bullet in the above list. However, this feature technically already exists. The Inspect Panel, which is displayed when the player right-clicks on a cell, provides a description of the cell contents and buttons for actions that can be performed. The buttons correspond to the items that would appear in the Cell Context Menu. Next week, I’m going to move the Inspect Panel from the center of the screen to the right side and add icons that match the Cell Action Indicator icons. I’ll also continue to work on the next major milestone, visibility.
The big news this week is that the Quick Switch Slots and Cell Action Indicators are done. I started on these exactly one month ago. They shouldn’t have taken this long to complete, but did because I had less time than usual over the past month and I underestimated the effort to code the features. They are two of the remaining three major UI features that need to be added (the third being Cell Context Menus).
Completed Quick Switch Slots. Quick Switch Slots are similar to a hotbar, but are used to quickly change weapons and other held equipment, and enable automatic switching of melee and ranged weapons based on the target’s distance from the player.
CompletedCell Action Indicators. Cell Action Indicators tell the player what will occur when a particular cell is left-clicked. An icon representing the action the player will perform is displayed when the cursor hovers over a cell. If the player first needs to move closer to the cell to perform the action, the Cell Action Indicator will display two icons, one for movement and another for the action to be performed.
Player input and action refactoring. The above UI changes touched one of the uglier parts of the code that is responsible for triggering in-game actions from player input. In the interest of finishing this game, I’m being more selective on rework. However, some rework was unavoidable this time. Previously, there were Player Actions (actions mapped directly to player input, which could translate to in-game actions such as moving the player’s character, or UI actions such as opening the Inventory Panel), Action Types (in-game actions), and Actions (instances of Action Types, but still defined as separate classes for each Action Type due to the evolution of the code). It was messy and redundant. I renamed Player Actions to User Commands, which helped me mentally differentiate these from in-game actions. I added a minimum and maximum range attribute to each action so that the Cell Action Indicators can determine whether the player’s character has to move in range of an entity before interacting with it, replacing some hard-coded logic that only worked in certain scenarios. I standardized User Commands and Actions behavior. I moved some methods into more appropriate classes. I fixed all the little issues that cropped up from the changes. I even found a couple of bugs that predated the recent changes.
Wand of Magic Missile. The Wand of Magic Missile was primarily created as a proof of concept for getting wands working, but will most likely stay in the game, and perhaps be a starter weapon for the Wizard class. I’m still deciding how to configure wands in terms of resource consumption. I’m leaning toward unlimited charges, no cooldowns, and eventual destruction from use. Wands will have to be underpowered to support this.
Next week, I’ll start working on the final remaining UI feature: Cell Context Menus. Right-clicking a cell will display a Cell Context Menu that lists all of the possible actions that can be performed on the cell (left-clicking performs the default action, as indicated by the Cell Action Indicator).
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.
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.
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.
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.
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.
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.
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.
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.
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).
Also, here are a few examples of the objects added last week:
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.
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.
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.
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.