The Obsidian Tower features a variety of enemies, but the cat boss holds a special distinction: it's the largest enemy in the game. While most enemies occupy a single tile, the cat takes up a 2x2 tile space. This seemingly simple difference introduced one of the more puzzling bugs I've encountered.
The Problem
During testing, I noticed that the cat boss wasn't behaving like the other enemies. Instead of chasing the player, it would consistently move toward the bottom-left corner of the room and get stuck there. No matter where the player stood, the cat would ignore them and retreat to that corner. Every other enemy worked perfectly — they would track the player and close in for attacks. But not the cat.
How the Movement AI Works
The movement AI for enemies in the Obsidian Tower uses breadth-first search (BFS) to find the shortest path from the enemy to the player. The algorithm treats the floor as a grid and explores outward from the enemy's position, avoiding tiles that are occupied by walls or other entities. Once it reaches the player's position, it traces the path back and takes the first step.
This system works great for standard 1x1 tile enemies. But the cat is different.
The Root Cause
Since the cat occupies a 2x2 area, it is tracked by its bottom-left tile — that's the tile used as its position for pathfinding purposes. The other three tiles the cat occupies are still registered in the game world as occupied spaces. Here's where the problem comes in: when the BFS algorithm scans the grid for obstacles, it sees those other three tiles as occupied — because they are. But it doesn't realize that those tiles are occupied by the cat itself.
In other words, the cat's own body was being treated as an obstacle. The pathfinding algorithm would try to route the cat around itself, which naturally pushed it toward the corner. Once in the corner, there was nowhere else to go — the cat was boxed in by its own collision tiles.
The Solution
The fix was to add a check in the pathfinding logic to distinguish between the current enemy and other entities. When the BFS algorithm encounters an occupied tile, it now asks: "Is this tile occupied by the enemy that is currently trying to move?" If so, it treats that tile as walkable rather than as an obstacle.
This allowed the cat to move freely through its own occupied tiles while still properly avoiding walls, other enemies, and other obstacles. After this change, the cat boss correctly tracked and pursued the player just like every other enemy in the game.
It's a good reminder that assumptions that work for simple cases — like every enemy being a single tile — can break down in surprising ways when you introduce even a small variation.