I started to add a new enemy this week, vampires. This revealed a problem with my AI framework. Vampires have the same move and attack behavior of a normal enemy, but they have some additional behaviors as well. For instance, they can change into a bat and will use that ability when their health is low to temporarily flee and regenerate health. Prior to vampires, the AI framework worked fine. Each time I needed to give an actor a different behavior, I’d simply add a new AI class. I had a single enemy AI class, a neutral NPC class, and a few classes for actors that do something but aren’t sentient, like fire and gas. This worked because the logic for each class was completely different. The vampire AI revealed a problem because it needed some of the standard enemy behaviors and its own unique behaviors. I spent a couple of days thinking about what to do about this. The solution came to me when I identified the pieces of the AI class that needed to change with each enemy: choosing which actors to track, choosing which observations to react to, and choosing an action from a list of potential actions. I defined interfaces for each of these and created standard enemy and vampire implementations. I extracted shared logic, such as determining all of the potential attacks an enemy has, into new classes so that the logic could be reused. I reduced the enemy AI class to the logic that was applicable to all enemies, which was mainly state management. I can now easily add new enemy behaviors without having to replicate code.
Rework can be a discouraging exercise, especially this far into a project. It doesn’t add anything to the game from a player standpoint. It doesn’t concretely move the project closer to the finish line, but there’s an expectation that it will save time in the long run. It can feed self-doubt (if I had written good code the first time around, I wouldn’t have needed to rework it). There’s a risk of over-engineering or building capabilities that you’ll never need. In this case, I almost scrapped my entire AI framework and considered implementing it using a Unity asset, Opsive Behavior Designer. I actually bought the asset and read the documentation. It seems like a great tool that provides a visual designer for AI behavior trees. It also supports utility AI within a behavior tree, which is essentially what my AI framework is doing in code currently. However, I decided to rework my existing code instead because it took less time to do.
With the AI rework filling up the week, the vampire wasn’t completed. I should be able to easily finish adding it next week. I’ll add one or two more enemies to test out the reworked framework. I will do the same with abilities, which went through a similar process recently of having to be reworked to support new types.
Momentum is picking up after a couple of slow weeks puzzling out the abilities architecture. With the architecture determined, I was able to implement the ability that triggered the architecture exercise in the first place, Heavy Strike. This ability is a melee attack that does more damage, uses a different animation and sound effect, and shakes the screen more. I wanted to be able to reuse the existing melee attack action for this ability. The solution was to add more parameters to the melee attack action and set the parameters from the Heavy Strike ability, which is a Unity ScriptableObject.
After finishing Heavy Strike, I started working on another ability, Charge. This ability performs two actions in a sequence, moving the player and attacking a target. It’s one of many abilities that perform multiple actions. This presented a new dilemma – actions were designed to be executed once per actor per game turn. The rework required to enable multiple actions per actor per turn was significant. I found a better alternative: Action Steps. Action Steps are now the basic building blocks of actions. They enable a series of actions to be performed within a single game turn action and make creating new actions and abilities a lot easier. Creating the Action Steps involves extracting code from existing actions. This is in progress. So far, Action Steps have been implemented for selecting a cell and shooting a projectile.
To control the execution sequence of Action Steps, I introduced another new object, Action Phases. Action Phases define the sequence in which Action Steps are performed. Each Action Phase contains one or more Action Steps. Action Steps within the same Action Phase are performed concurrently. This allows Action Steps to be performed sequentially, in parallel, or with a combination of the two. Some actions, such as pushing and pulling, require parallel execution of Action Steps.
Next week, I’ll build a few more Action Steps (moving and attacking), which will allow the Charge ability to be created. I should be able to quickly add some more abilities. I’ll also post the pixel artist ad in a few new places.
It was an ok week. I had the same issue that I had the previous week – nothing got done during the weekdays.
Abilities architecture overthinking. I’m spending way too much time figuring out the architecture for abilities. I have a vision for a clean, highly-extensible, Unity editor-driven solution but I haven’t been able to get there. This weekend I’m forcing myself to finish this and move on. There are plenty of ways for me to accomplish this goal that aren’t perfect but are workable.
Saving/Loading working again. Saving/loading has been a pain point throughout development. Many changes break it, causing me to wonder if I’m going about it in the correct manner. Since I don’t often test saving/loading, when I do test, there are always a few issues to fix, and these issues are usually not simple fixes. Testing saving/loading every time I make a change would be too cumbersome; maybe I’ll add automated testing of this feature in the future. Anyway, saving/loading is working again. Since I’m reworking the code less these days, I expect to have fewer saving/loading issues in the future.
Rework – cell selection support in actions. Many actions (melee attack, ranged attack, open, take, drink, etc.) require a target. In the main game context, the target is determined by where the player clicks. In other contexts, such as clicking an item in the hotbar, the target is determined by prompting the player to select a cell. Early on, I built the cell selection handling into the ranged attack action. I knew I’d have to eventually extract it but I wanted to get ranged attacks working quickly and I wasn’t clear on all the other potential uses of cell selection. This week I moved the cell selection code into its own class and made it easy to use from any action.
Fixed some non-fatal, recurring exceptions. I got tired of seeing the same errors in the logs on every playthrough. They didn’t actually break anything in the game, but they cluttered the log. I removed the several most common errors.
Wrote the first half of a post on time-tracking. Last week I stated that I was going to post the findings from meticulously tracking my game dev time over the past four weeks. There are some interesting observations but I realized that I need a larger sample size for some of those observations to be meaningful. I’m going to collect another four weeks of data and reassess if I have enough for a post.
Next week, there will definitely be some new abilities in the game.
I got off to a great start last weekend, but the weekdays were consumed by my full-time job. I now have four weeks of time tracking data and will share a separate post on that in the coming week.
New ability: Fireball. This ability shoots a projectile at a nearby cell and creates fires in the 3×3 area around the cell. Much of the implementation effort involved supporting code rather than the ability itself. The Create Actor Effect was extended to allow actors to be created in multiple cells at once. I consolidated the Effect.Cause(Actor) and Effect.Cause(Item) into one method, Effect.Cause(Entity) (the Entity class was introduced as a parent of Actor and Item after writing the Effect code. I fixed existing bugs – items in cells weren’t being destroyed by fire, the select cell prompt was wrong, etc. All this work will make implementing other abilities that are projectile-based spells easy to implement. In most cases, this type of ability can be created exclusively in the Unity editor.
Refactoring: StandardMeleeAttackAction class. Melee-based abilities vary in terms of targeting, area of effect, sequence of events, animation, and stat modifiers. I’m still determining how to architect a solution that enables melee abilities to be easily created, modified, and maintained. The starting point is the StandardMeleeAttackAction class, which is responsible for executing standard melee actions. It actually does much more than it should, and the things it does are the building blocks for the melee-based abilities. I cleaned up this class and moved a lot of the logic into other classes for better reuse.
Pixel artist job ad. I’m at the point where I need to start getting original art in place. It’s going to take some time to find an artist (or artists), and much more time to create the new art assets. I wrote a job ad for a pixel artist and will post it in a few places next week..
Next week, I’ll finalize how melee abilities will be implemented and build out one or two melee abilities. I’ll also post the pixel art ad.
This week, I started on the next milestone, abilities. Abilities include special attacks, spells, utility skills, and passive effects. I have a list of around 90 abilities currently and expect the final count to be between 120 and 150. Each actor (player classes, NPC’s, enemies) will start with zero or more abilities. Players can gain more abilities over the course of the game. I haven’t worked out all the details, but the ability acquisition will be integrated into gameplay (i.e. they can be found like items, or learned from an NPC) as opposed to a skill tree. Like items, the abilities placed on the map get stronger the deeper the player goes. The abilities available to the player depend on the player’s class. Each class has a set of attributes and a maximum proficiency level for each attribute (basic, intermediate, advanced). Each attribute proficiency level is associated with a set of abilities. A class is able to use the abilities defined for each of its attributes, at or below the proficiency level defined for that attribute. For example, a Ranger has a Weapons (Intermediate) attribute that allows use of the abilities associated with the basic and intermediate proficiency levels of the Weapons attribute.
Reworked abilities and attribute classes. Basic ability and attribute functionality was already in place to display attributes on the class selection screen and display abilities available to the player. To fully support the ability system, the underlying code had to be extensively reworked. Most of this week’s time went into this rework. Active and passive abilities were split into separate classes inheriting from a common base class. Relationships between attributes, attribute proficiency levels, and abilities were rewired. Attribute ScriptableObject assets were condensed from one asset per combination of attribute and proficiency level to one asset per attribute to directly group abilities for each proficiency level (this is useful because classes have access to abilities for a maximum proficiency level and all proficiency levels below the maximum).
Improved Abilities Panel. The Abilities Panel previously displayed all available abilities in a single grid. Now the panel has a tab for each Actor Attribute and the abilities for the selected attribute are grouped by proficiency level.
Miscellaneous ability-related enhancements
Starting abilities automatically added to the hotbar.
Abilities can be inspected like entities and cells.
Contemplated replacing abilities with items. This is more of a side note than an update, but midweek I stopped development and seriously considered implementing abilities as items. The origin of the thought was my struggle to determine how resource consumption will work with abilities (I still haven’t figured this out, by the way). One option was to simplify and consolidate resource management to inventory. Players would find items that did the same things that abilities would do – a scroll to cast a spell, lockpicks to pick a lock, etc. This idea appealed to me because clever use of what you find is key to success in the game, and it avoids using time as a resource (waiting to regenerate mana/stamina). But, there are drawbacks: 1) the desired player behavior is to frequently use abilities, but having a finite number of uses and uncertainty about how many future uses the player will have encourages hoarding 2) it’s difficult to allot uses of large quantities of items over the course of the game. Because of the drawbacks, I rejected the idea and resumed work on abilities as planned.
Next week, now that the abilities system is complete, work will begin on the abilities themselves. The big challenge here is implementing many abilities in a scalable manner. I want to avoid creating a separate class for every ability, and I want to leverage existing objects like actions and effects as much as possible.
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.
There’s not much of interest to report this week. Last week I implied that there wasn’t much work to do on Cell Context Menus because they technically already exist – the Inspect Panel lists the actions that can be performed on the entity being inspected. However, not all of the actions were listed. I couldn’t simply add the missing items because they are implemented in a different manner than the actions that were being listed. Specifically, the missing actions inherit from the UserCommand class and the included actions inherit from the ActionType class. I decided to simplify things by having actions inherit from ActionType, and limiting the purpose of UserCommand to mapping input to actions. This led to a lot of rework.
Item light sources for non-player actors. Actors other than the player now display light sources from the items they’ve equipped.
Dropped torches. When a lit torch is dropped, it now stays lit and maintains its light source. When the player picks up the torch, the torch is added to inventory as an unlit torch and the light source is removed.
Quick Switch Slot improvement. When no item is selected in a Quick Switch Slot, the deselect option, which is redundant in this scenario, is no longer shown.
Bug fixes. These were mostly issues introduced by this week’s extensive rework rather than long-standing issues.
Refactoring. I used the rework as an opportunity to refactor where it was easy to do. This included cleaning up some classes and method extraction.
Contemplated a name change. “Legend” is the third name that this game has had. I’m considering changing it after recently watching a video on naming your game. My concerns are that “Legend” is too generic, too hard to search for, and has copyright risk. I made a list of words that convey some aspect of the game this week. None of them jumped out at me. I’ll keep adding to the list and playing around with different combinations until something clicks.
Next week, there’s some more rework testing and cleanup to do. I also need to make minor refinements to some of the recently added features.
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).
It was a solid week with lots of smaller, but important, improvements and fixes. I added a few new map features and need to make sure that I do this every week, because map content variety is one of the key aims of the game.
Fibonacci weighted randomization. This is an extension of the existing weighted randomizer that adds the capability to automatically set weights based on fibonacci numbers. I created this because I kept needing a random number generator where each outcome was less common than the outcome before it, and the number of possible outcomes was variable. Fibonacci numbers naturally worked for this. I start at the second 1, so the outcome weights are 1, 2, 3, 5, 8, 13 and so on, and the weights are assigned in reverse order so that the most common outcome has the largest weight. I use this primarily for rarity-based random selection.
New sound effects. I added sounds for hitting webs, stalagmites, and bones and an ambient looping sound for braziers. The physical material-based sound effect configuration, in which the sound played is based on a combination of the weapon used and the physical material of the target, is becoming unwieldy. I will probably remove weapon-specific sound configuration and create a global configuration based on combination of weapon damage type (slashing, chopping, bludgeoning, piercing), weapon physical material, and target physical material.
New Map Elements. Added statues, grass, pots, and rugs.
Removed redundant Map Elements. Some common patterns emerged as I continued to create new Map Elements and it became evident that I could combine some of the elements. For example, there were dedicated elements to place a single actor such as a fountain or a shrine. The only difference between the elements was the actor. So, I removed these variations and created a single Actor Map Element that takes an actor type as a parameter.
Rubble tile variations. I got really tired of seeing the same rubble tile everywhere. I bought the Oryx 16-bit Sci-Fi sprite set primarily because it has two more rubble variations (that’s how much I like making my own art). The variation helps, but some of the rocks are too big. I’ll live with it because all the artwork is going to be replaced anyway.
Player corpse. When the player dies, there’s no visible indicator beyond the “Game Over” message. So, I made a corpse sprite (for the Knight; I still need to do the other player classes). As with the enemy corpse sprites I made, I used a simple process of rotating the sprite 90 or 180 degrees, slightly shearing it, and dropping the blood sprites above or below. The results are ugly but serviceable. Now when the player dies, a corpse will be displayed.
Animated Bones improvements. Animated Bones, which are piles of bones that come to life when the player approaches them, were improved. Now they animate when the player is diagonally adjacent to them and when the player attacks them from a distance with a ranged weapon.
Equipment hotbar design. Over the past few weeks, I’ve been thinking a lot about how melee weapon switching and ranged weapons should work from a UI standpoint. This week I finally figured out how this should be designed. I still need to implement the design to validate it.
Added unit tests for select utility classes. I practiced some test-driven development this week, which is a rarity. I found some issues with the Fibonacci randomizer right out of the gate, so the new unit tests already paid for their effort.
Bug fixes. Fixed ~10 issues that directly affected gameplay, which felt very satisfying.
Next week, I expect to mostly work on UI, specifically the melee and ranged weapon hotbars.
Most of the improved AI and game event response was built out this week.
Field of view for game events. Returns a list of the cells that can see an event. For each cell, the distance from the cell to the event is also calculated so that actor sight distance is taken into consideration.
Game event notification optimization. Previously, each actor received a notification for each event, and then determined whether the event was in the actor’s field of view. Now, only the actors in the game event field of view are notified, and only a quick sight distance check needs to be done.
Door opening and closing game event reactions. Actors now respond to doors that they can see open and close. They will walk to any door that opens or closes (other behaviors will be added in the future). This allows for player tactics like luring an enemy into a vulnerable location, or away from a guarded location.
Preoccupied and Observing awareness levels. Actors in the former state must wait one turn before reacting to a game event. Actors in the latter state can react in the same turn. So, when the player enters a room with guards who are actively observing, the guards can respond immediately.
Refactoring. Consolidated duplicate code and extracted some classes in the actor action code. I’ve been reading Clean Code and getting some good refactoring ideas.
Optimizations and bug fixes. The recent changes introduced slowness and some undesirable behavior (enemies attacking each other, enemies attacking doors, enemies attacking dead enemies).
11/30 is the target date for Release 3. The goals of Release 3 have largely changed since it was originally scoped six months ago. The last milestone is completing the AI game event response system. I should be able to complete this in the coming week.