Quick answer: Tower offense inverts tower defense: your units march down lanes to attack enemy positions, so the bugs cluster in pathing, wave composition, and targeting. Track each unit's path and target, the composition and timing of the wave you sent, and the lane state when an assault stalls. Capturing that lets you replay the wave and see why a unit got stuck, walked past its target, or stalled the whole offensive.

Tower offense takes the comfortable logic of tower defense and turns it inside out: instead of placing towers to stop a horde, you compose and send waves of your own units to break through enemy lines. That inversion moves the bugs around. Now your units do the pathfinding, so they are the ones that get stuck on geometry, clump at a chokepoint, or pick a target on the far side of a wall and refuse to move. A stalled offensive looks like a balance complaint but is usually a pathing or targeting defect. This post is about capturing the wave and lane state so you can see why an assault failed.

Your units do the pathing now

When the player's units are the ones moving, every pathfinding flaw becomes a gameplay bug they will report. A unit that catches on a corner of collision geometry, a group that funnels into a one-tile gap and deadlocks, a flyer that ignores a wall the pathfinder thought was solid: all of these stall the assault and look, from the player's seat, like the unit is simply broken or stupid. The lane layout, the obstacle placement, and the navmesh are now your highest-risk surfaces because the fun depends on units reliably reaching the enemy.

To debug this you need each unit's intended path and where it actually stopped. Log the computed path, the unit's position over the last few seconds, its current movement state, and what it believes it is doing. A report that my army got stuck becomes actionable when you can see that twelve units all halted at the same map coordinate with a path that routed them through a gap one unit too narrow. Pathing bugs are deterministic given the map, so once you can see where they jam, the navmesh fix is usually straightforward.

Wave composition is the input that broke

In tower offense the player's main lever is which units they put in a wave and in what order, so the wave composition is effectively the input that produced the bug. A wave of fast melee units behaves nothing like a wave of slow siege units, and a bug may only surface for a specific mix, for example when a healer is placed behind units that outrun it, or when two unit types have a targeting interaction that loops. If you do not capture exactly what the player sent, you are trying to reproduce an output without knowing the input.

Record the full composition: the unit types, their counts, their order, and the spawn timing of the wave that failed. With that you can resend the identical wave in a test map and watch the same breakdown unfold. Composition data also reveals balance problems masquerading as bugs, the wave that always loses because the player keeps making the same structural mistake, which is a design and tutorial issue rather than a code one. Either way, the composition turns a vague loss into a precise, replayable scenario you can study.

Targeting, walls, and stalled assaults

Targeting is where tower offense quietly breaks. A unit picks a target by some priority, nearest, lowest health, highest threat, and a bug in that logic can send it walking toward an enemy it can never reach because a wall blocks the path, while ignoring the tower right next to it. The assault stalls not because the units are weak but because they collectively decided to attack the wrong thing. These bugs are invisible in a screenshot and easy to misread as the player just losing, when really the targeting system steered the whole army into a dead end.

Capture each unit's chosen target and the reason it chose it, plus whether a valid path to that target exists. When you can see that an entire group selected an unreachable structure and stood there, the bug names itself: targeting must verify reachability before committing. Log the target reassignment events too, since flickering between two targets every frame is its own performance and behavior bug. Seeing the targeting decisions as data is what separates a fixable logic defect from an endless argument about whether the level is too hard.

Spawn timing and the order units arrive

Tower offense leans heavily on timing, because a wave is not just a bag of units but a schedule of when each one enters the lane. A spawn-timing bug can release a fragile support unit ahead of the tanks meant to shield it, so it dies before the assault forms, or it can bunch units that were supposed to stagger, turning a planned push into a clump that an enemy splash tower wipes in one shot. The player sent a sensible wave and watched it dissolve, and from their seat it looks like the units are weak rather than mistimed.

So capture the actual spawn schedule the wave executed, not just the composition the player chose, because the two can differ when a timing bug reorders or compresses the release. Logging each unit's spawn timestamp against its intended slot shows immediately when the scheduler fired out of order or collapsed the gaps. Timing bugs are deterministic given the wave, so once you have the real schedule you can replay it and watch the same premature spawn happen, then fix the scheduler rather than blaming the unit stats that were fine all along.

Setting it up with Bugnet

Bugnet's in-game report button can fire when a player flags a stalled assault, carrying the wave and lane state with it. Push the wave composition and spawn order into a custom field, the per-unit path and target data into player attributes, and the map and lane identity alongside, so a report arrives as the exact offensive that failed rather than a complaint that the level is broken. You resend the captured wave on the captured map in a debug build and the stall reproduces, with each stuck unit's path and chosen target right there to read.

Because the same chokepoint or targeting flaw traps many players, Bugnet's occurrence grouping folds the duplicate stall reports into one issue with a count, ranking which lane or which unit interaction is costing the most players. Filter by the map, by the unit type involved, or by the coordinate where units jam, and a pattern surfaces quickly: every clustered report shows units halting at the same narrow gap. One dashboard turns a scatter of my army got stuck messages into a prioritized list of navmesh and targeting defects with the inputs needed to reproduce each one.

Testing waves like deterministic scenarios

The teams that keep tower offense feeling fair treat each wave as a deterministic scenario they can replay. Build a harness that takes a map plus a wave composition and runs it headless, asserting that units reach the front, that none get permanently stuck, and that targeting never selects an unreachable enemy. Seed it with the real failing waves players send, and every navmesh or targeting fix gets a regression test that stops the same jam from coming back in a later patch. Determinism in movement and targeting is what makes those assertions meaningful.

Culturally, push the team to separate balance feedback from bug reports early, because they look identical on the surface and need opposite responses. A wave that loses to good enemy placement is balance; a wave whose units walk into a wall and stand there is a bug. The captured path and target data makes that call obvious. Get into the habit of replaying reported waves, and the inverted formula of tower offense stays satisfying instead of collapsing into a pile of stuck-unit complaints you cannot tell apart.

Tower offense inverts who does the pathing, so your units carry the bugs. Capture the wave you sent and each unit's path and target, and the stall explains itself.