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.

Just a Few Performance Optimizations

It’s not going to be productive to spend lots of time optimizing code at this stage, because things are still pretty fluid. I like to save detail work until later in the project. But today was devoted to some quick optimizations of the AI, pathing, and collision check routines.

Over the IndieCade weekend, I tried a few of the pathing exhibition levels on my laptop on battery power, and it went down to about 1 FPS once all 50 rats were on the screen. I was expecting this, since I didn’t put any effort into performance yet–I just wanted to get it working.

Visual Studio 2012 impressed me with its performance and memory profiler. I was able to quickly see what the slowdown was being caused by. It’s mostly collision detection, as usual, but the traffic field system was also grinding things down. The vision checks are pretty much the biggest culprit, because they do multiple collision tests per frame to check if one creature can see another.

There are some more robust solutions I can do later, but I only wanted to spend one day on it, so:

  • Traffic field builds itself for entire map, rather than dynamically as creatures move.
  • Vision field keeps separate lists of monsters and heroes so it doesn’t need to do checks or filters in the “detect foe” vision checks.
  • Position comparison checks reduced by bailing out earlier for most cases (early returns from functions when it doesn’t make sense to do further tests on the actor).

Just the above cut the time spent in the update routine by about half. Meaning… on battery power, the torture test levels run upwards of 2 FPS!  Okay, so there’s more to do (most likely a bucketing system to split the room into sectors, like Escape Goat). But this will do for now–I mainly wanted to make sure none of the systems I developed were going to pose such a performance threat that they would need to be removed later.

Off The Grid: Research Complete

After a quick rewrite of the collision detection system, and a couple extra AI systems that aid in pathfinding (more on that in a future post), I’ve got the monsters working just how I need them to.  Even with a super fast spawn rate, they don’t overlap, and if they get deadlocked trying to get into a doorway from opposite directions, they will back off after a moment and retry.

With omniscient pathing turned on, the rats are completely unstoppable.
With omniscient pathing turned on, the rats are completely unstoppable.
This is with pathfinding disabled, and AI set to move Gauntlet style (always towards the player).
This is with pathfinding disabled, and AI set to move Gauntlet style (always towards the player).

The Grid, Continued

I couldn’t shake the idea. This morning, my first order of business was trying out pixel-based movement for the Summoner.

It actually seems to work really well. Even placing summons felt natural–I’m having them align to a grid, double the resolution of the tiles, to keep it tidy. It’s actually a lot like how Escape Goat handled a combination of tile grid and pixel accurate movement. Now Aeox can block a two-tile wide corridor… we’ll see how that changes things at the micro level.

Enabling pixel based movement for the monsters opened up a can of worms. Since they swarm so close to one another, I had to bring some of what I learned about collision resolution from Escape Goat, to keep them from merging and overlapping. It brought me back to the good old days of 2011, when, for months on end, every SVN checkin was noted as “collision hell”. I can probably keep this visit much shorter (though I said that to myself every day back then). Collisions are nowhere near as complex as Escape Goat, so basic AABB testing should do the trick.

I’m looking forward to seeing how this will look with dozens of monsters packed tightly together–should be reminiscent of Gauntlet.