3 min read

Developers Hate It! See How This Door Caused Hours of Debugging with One Simple Trick

Developers Hate It! See How This Door Caused Hours of Debugging with One Simple Trick

A notable amount of bugs have been uncovered in the last week and caused some notable set backs (thankfully all fixed now). One particularly painful bug though revolved around this block and how it mysteriously would cause all NPCs to freeze in place:

A screenshot of the block that revealed the bug

This particular level requires a user to unlock a door before being able to progress into the second half of the map. Upon entering that second half, there are two ways to progress further and both require destroying an obstacle:

A top down view of the map illustrating the path the player must take to reach the problematic obstacles

Once either of those obstacles are destroyed, it results in the navigation map that the enemies use to move around the level to be rebaked. As soon as this happens, they would freeze in place unable to move.

Little did I know, I had seen the issue earlier in the day, and didn't connect the two things. Earlier, the enemies began to sink into the floor, which seemed strange. I "solved" this by altering the calculated velocity so that the Y value always remained at 0 (given the levels are all flat), like this:

var next_path_position: Vector3 = navigation_agent.get_next_path_position()
next_path_position.y = global_position.y
var new_velocity: Vector3 = global_position.direction_to(next_path_position) * movement_speed

Problem solved! Or so I thought; in reality, all this did was create the new bug, which would make the NPCs freeze in place.

The first thing to figure out was why they were freezing in place. As I hadn't connected the change I had made earlier to the current issue, it wasn't initially clear, but the reason they were stuck in place was because the next position being returned by the navigation agent (using get_next_path_position()) was directly below the current position of the NPCs, but as the Y velocity was being reset to 0, they were never moving down and reaching the next point.

After realising this was all down to the bug I thought I had already fixed, the question remained... why on Earth is this happening!?

When testing in the first half of the map, it was outright not possible to replicate the problem. The only thing that would cause the NPCs to start trying to move beneath the ground level, was destroying one of those two obstacles in the second half of the level.

From a code perspective, it made no sense. There was nothing unique about those obstacles. Nor should them disappearing affect the navigation map in a way that would give it extra height.

After hours of testing and debugging, I realised what was unique about destroying those two obstacles compared to all the others - this door!

The door that caused the navigation map issues

The player has to open this door to get to the second half of the map. When it opens, it sinks into the ground. When it does this, it doesn't result in the navigation map being rebaked, as there is no need for it; or so I thought...

As It turned out, the collision layer of the physics body for the door was incorrectly set resulting in the door being included when baking the navigation map. This meant that the player would open the door, moving the physics body mostly below the ground level and then the next time the player destroys an obstacle and forces the navigation map to be rebaked, it would do it with the door's physics body below the ground.

Why exactly this caused NPCs on every point of the map to start trying to move below the ground level? I can't say, but it was changing the height of the map being calculated by Godot.

All those hours of debugging were ultimately fixed by changing the collision layer... i.e. changing a number from 1 to 18...

The lesson to take from this? Make sure to carefully consider which objects are in your navigation regions, and if trying to keep a completely flat navigation map, make sure anything moving below the ground level is not included in future bakes of the navigation map.