Debug Visualizations & Tile Blending

With each project, I put a bit more time into debugging visualizations. I just try to look for things I spend time debugging a lot (where I step through code) and making sure there’s a quick way to show how things are working.

The most basic is the hitbox visualization, which shows world geometry (walls are red, trenches are yellow) as well as actor hitboxes. The monster hitboxes change color when their AI switches from pathfinding to Gauntlet movement (when they are in line of sight).

This is where you can see a few different layers of the pathfinding AI. The blue blob following the summoner is the vision radius. When monsters step on it, they switch from using pathfinding to directly walking towards the player. The numbers in the top right of each tile are the step values for the path map. They actually represent how many tiles away the target is, in this case the summoner. The numbers in the bottom right of the blue blob are the priority levels for the vision. Because summons also broadcast pathing and vision fields, each tile needs to have a specific target based on distance.

Finally we have the targeting radius. This is built just like the radius above, but it’s not obstructed by trenches. It’s used for the archer to pick targets. In the previous Soulcaster games, NPCs would fire off “line of sight” tracers to find targets. Because of how expensive these were for the CPU, they would have to be restricted to intervals of once or twice per second. This just made the AI slightly less responsive. This system is instantly responsive and by my guess, uses about 10% of the CPU power.

Not a debugging feature, but it’s something I just finished today and think is pretty cool. Since the levels are generated from basic elements, I have to teach the computer to do all the nice tile blending I did by hand in the previous games. It’s a fun challenge. This test just shows 16 different blend tiles which use the cardinal directions. To get rid of the divots in the corners of solid walls, I’ll need to add support for all 8 adjacent tiles. This can be used all over the place, for both natural and artificial architecture.

Excitement

I’m constantly coming up with ideas for whatever game I’m working on. I never have time to try them all, so I tend to bank the riskier ones for use in a sequel. But we’re still in the prototype stage in Soulcaster 3, so it’s the perfect opportunity to test a new combat idea I had last week. Once I saw this in action, I felt an excitement I haven’t felt yet in this project.

Sorry for the tiny file, WordPress is acting up and not allowing files larger than 3MB.
Sorry for the tiny file, WordPress is acting up and not allowing files larger than 3MB.

OG Soulcaster players will immediately see what the difference is here. Instead of recalling summons one at a time and placing them only when you have an orb available, you can now queue up “future summons” with markers. As the existing summons are recalled or destroyed, the orbs powering them will look for a marker to inhabit and spawn a new summon. If there aren’t any, the orbs zoom back to the player.

I haven’t exhaustively tested this yet, but in basic test arenas, it allows for much more strategic play. In the original games, if your defensive line collapsed and you had to reform your summons in a good formation, you were struggling to place them while kiting enemies, and since they appeared one at a time, they were way less effective. This way, you can have a whole new formation set up ahead of time to get back on your feet quickly.

Even better, it gives the player something to do while the guardians attack the enemies. You can choose where to take the battle next based on which monsters are appearing.

One new challenge with this system is what to do if the monsters walk over the markers before the orbs get to them. Should they get destroyed? Or do they only break if the orb reaches them and a monster is still walking over them? There are only a few options for what to do, so I will just try out a few things and see what feels best.

Equipment Systems Improvement

Part of rapidly putting together a prototype is knowing that, at some point, I’ve got to go back and clean up the code. Make it work, first, then make it work right (and finally, make it work fast if you need to). Before I can go any further it’s a good idea to clean up the code and solidify one of the most fragile systems, which is the equipment/weapons/attack generation code.

Vision Field Improvement

I had a bit of inspiration for how to dramatically simplify vision checks in the game.

Vision checks are used in two situations:

  1. Ranged summons (archer and bomber) look for a suitable target
  2. Monsters check if a hero is directly walkable, so they switch from pathing to Gauntlet style movement

These checks are very expensive for the CPU, because they have to iterate to check for obstruction with the world and other actors in the scene.  I realized that we don’t need this level of precision for monster hunting behavior–tile-based granularity is fine, and since there are few targets (summoner and summons), it’s best to broadcast vision from these sources rather than do constant checks.

Pillars obstruct sight. Monsters on blue tinted tiles will move towards player instead of using pathfinding.
Pillars obstruct sight. Monsters on blue tinted tiles will move towards player instead of using pathfinding.

In this new system, every time the summoner moves to a new tile, it calculates which tiles are visible from that position. Monsters only need to check if they step into one of these zones, and this check is only done when they move from tile to tile. Even with the brute force evaluation of visibility, this is probably 50x faster than the old system. (If it needs to be optimized, there is no shortage of methods for calculating vision).

As a side bonus, the monsters don’t need to be on an interval timer for sight checks. It always checks just when it needs to (on a tile change). There were problems before with monsters stepping too far away from the player because their vision timer hadn’t reset yet, and they were still pathing to a stale position. Now they are way less likely to be confused and aimless at close range.