The bugs keep crawling out. I’m fixing them and finding new ones at about the same pace. On the bright side, they’re getting easier to find. I usually know where to go or at least where to start now. I don’t know if that’s the result of the code improving or me starting to recognize where the common problem areas are. Bugs are also getting easier to fix. Often I simply have to change a configuration value or modify a single line of code rather than having to do major rework or implement a system I didn’t anticipate. However, I’m spending 25% of my dev time on bugs and that is too high. To lower this percentage, I’m allocating more time for automated test development. My strategy is to incrementally add tests from a master list of test cases, and add tests related to the bugs I find.
A major achievement this week was reworking interactions between entities in the same cell. This was originally handled in the following manner:
- When an entity enters a cell, it applies its interaction effects to all existing entities in the cell, and all existing entities in the cell apply their interaction effects to the entering entity.
- Each turn that entities co-occupy a cell, their AI reapplies interaction effects. For example, a fire will continue applying a burning status effect to each entity in the cell.
- When an entity exits a cell, the interaction effects it caused are removed from the remaining entities in the cell, and the interaction effects caused by the exiting enemy are removed from the remaining entities in the cell.
This implementation had a few limitations. It prematurely removed some status effects, such as poison, that have a multi-turn duration. It required effects to be applied by the AI, which never conceptually made sense. Because it relied on AI to apply effects each turn, it hurt performance because it increased the number of entities that acted in each turn. For example, in a room filled with poisonous gas, the gas in each cell acted in each turn. To address these limitations, I did the following:
- Added a game service to manage per-turn interactions between entities occupying the same cell, allowing efficient interaction handling on each new turn.
- Added a new effect trigger that only occurs when two entities interact for the first time. This is used when the player walks onto spikes, for example. The player is damaged when walking onto the spikes, but will not be further damaged while remaining in the cell containing the spikes.
- Removed the logic that removes effects when an entity leaves a cell.
- Removed the AI logic that applies effects each turn (this is now handled by the interaction manager).
I added a new Map Element, Darkness. When the player walks into a room with Darkness, visibility becomes limited to the adjacent cells. This is intended to be an unnatural or magically-induced darkness, as opposed to normal darkness. It’s not fully working yet. When the player opens the door into the room, all of the room cells the player can see from the doorway are visible. I need to fix this.
The most difficult bug I fixed this week was in the grid traversal raycast algorithm, which is used for line of sight and projectile calculations. Sometimes, arrows didn’t travel to the cell the player clicked. It wasn’t obvious why this was happening, and it wasn’t a major problem, so I didn’t do anything about it for a long time. Now that I’m fixing all of the known bugs, I decided to tackle it. I traced the issue to a method that calculates the final position of a ray (a projectile or light) given a start and end point. The algorithm used is similar to Bresenham’s line algorithm, but it includes every cell that the ray passes through. I can’t remember when I added this algorithm, but it’s been in use long enough for me to have forgotten when I started using it. So, I was surprised to find that there was a problem in it (I should have written unit tests for it). I spent a couple of hours adding debugging statements and tracing through the code. I could see that the algorithm was generating the wrong points, but I couldn’t figure out what I needed to do to fix it. I got out some graph paper and sketched an example. The visual representation was much more helpful than the code. There were actually two errors in the algorithm. The code fixes were trivial at that point.
Next week will be 40% bug fixing, 40% automated testing, and 20% feature development. The feature development will involve expanding the types of interactions between entities. There’s already a framework for this based on the primary physical material that an entity is made of, but more interactions between materials need to be defined (for example, when fire hits a cell containing a puddle).