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.

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.

Summoner AI and Balancing

With all three summons operational again, now begins the task of finding a good starting point for balancing.

The obvious things to tune are the values for creature health, damage, attack rate, etc. I use spreadsheets to do this sort of thing:

spreadsheetThe orange headings are the creature’s attack stats, which can be used to compute the outcome of an encounter. Those are in green. For example, with these stats, Shaedu can slay 0.44 skeletons per second provided direct shots and the ability to attack at full range.

The mitigated damage value is how much the creature would damage an armored foe. I’m currently just using an armor value of 2, which reduces damage of each attack by 2. This means lower attack power is severely reduced compared with strong attack power (compare the skeleton’s DPS drop from 4.50 to 3.00 with the rat’s DPS, which is being slashed from 4.80 to 2.40).

This spreadsheet is only really useful as a starting point, because there are so many other variables that impact on a creature’s effectiveness and survivability. Choke points are where Bloodfire does best, because the bombs hit multiple foes if they are clumped up. Shaedu does great in corridors where the monster has to head directly into the line of fire–given a slow enough release rate, she can actually take out an infinite number of skeletons or rats. And Aeox is most effective in 1v1 attacks, foe example, when he is guarding a doorway.

Before fine tuning these values, I have to decide on which AI features the summons have. For example:

  • Can Aeox start an attack on an approaching monster before they are in range to strike back? This makes an enormous difference if he is just cleaning up wounded foes by last-hitting them. It means that if monsters come in one at a time with less than 6 HP, he won’t be damaged by them. (I do plan to add this pre-emptive strike, because I think this is strategically cool).
  • Do Shaedu and Bloodfire lead their shots? Until today, they just fired at the monster’s current position. Fast-moving rats, when they are running laterally, become impossible for her to hit, because in the 10 frames it takes the arrow to arrive, the rat’s already moved away.

To calculate the shot lead, it just looks at the monster’s current velocity, calculates how long it will take for the arrow to reach the target, and looks ahead that far in the future to shoot where the monster will be.

Of course, if the monster changes directions or stops, the shot might still miss. This is so effective, I’m curious if it should be a powerup, or just natural behavior.  In a scenario like this, see how much difference it makes:

Without leading the shot
Without leading the shot
With leading - See all those direct hits
With leading – See all those direct hits

The next step is to create a few test maps and see how well the summons do in a variety of room layouts. It’s important that they be considered roughly equivalent in their effectiveness.  The synergy is even more important–Aeox and Shaedu working together, with proper placement, will take out twice as many foes as they would if they were placed one after the other.

Feature restored: Aeox and Shaedu Attacking

As is usually the case with a major code overhaul, I disabled many features so I could test stuff out and get it working with each existing system, one at a time. One of the final things I need to restore is the summon AI for targeting and attacking enemies. Their behavior is slightly different from monsters, because they never move to reach another target, but it uses the same code at least.

attacks1

So far, Aeox attacks properly (now with 8-way attacking!) and Shaedu also aims and hits properly. There’s still an issue with her firing trick shots at moving targets between obstacles (like through a doorway if the monster walks past it), which probably has to do with her search interval and vision check code. Something to fix tomorrow, along with the Bloodfire attacks.