godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.21k stars 21.21k forks source link

NavigationAgent2D has repath loop issue #95628

Closed rob1gat closed 1 week ago

rob1gat commented 3 months ago

Tested versions

System information

Godot v4.3.stable - Linux Mint 21.3 (Virginia) - X11 - Vulkan (Forward+) - dedicated AMD Radeon RX 6700 XT (RADV NAVI22) - 12th Gen Intel(R) Core(TM) i5-12400 (12 Threads)

Issue description

In this scenario, Blue Godot wants to go to Green Godot : nav_issue_1

But Blue Godot is stuck in place as it constantly hesitates between 2 paths : nav_issue_2 nav_issue_3

Blue Godot _path_desireddistance is equal to 10. If I set the _path_desireddistance to 20, Blue Godot manages to choose the lower path, but crosses the red obstacle.

This scenario is a simplification of a more complex scenario that suddenly happened in a complex project, with multiple NPCs that constantly use navigation in various scenarios. I tried to adjust _path_desireddistance in my project but when I set it higher it breaks on other scenarios (basically, when I set higher values, NPCs paths sometime cross obstacles but NPCs cannot cross these obstacles due to physical collision).

About this simple scenario, I don't understand how I can end in a repath loop since Blue Godot does not seem to overshoot distance to the next point. Is it kind of a path finding heuristic edge case ?

Steps to reproduce

Just run the MRP

Minimal reproduction project (MRP)

mrp_nav_repath_loop.zip

smix8 commented 3 months ago

Thanks for reporting. This not an engine bug but a responsibility of the script coding to fix.

The reason why it is even happening is because the script sets a new target position every single frame.

This queries a new path everytime and resets the entire path every single frame. In turn this breaks every consistency in the movement. Querying a new path is not something that you find in the official documentation script example for this very reason. It is also mentioned in the documentation under the common agent issues with more info why it is happening. https://docs.godotengine.org/en/latest/tutorials/navigation/navigation_using_navigationagents.html#pathfollowing-common-problems

So what should be done instead is to only update the path when necessary , e.g. by a distance check when the target has moved to far away from the current target position, or with a timer that does not fire every single frame. This will also improve performance so for the hypothetical complex project this will be a necessary step anyway.

rob1gat commented 3 months ago

Thanks for your fast and clear answer.

I updated my code by adding a distance check and it works now.

For some reason, I was thinking that the entire path was reset each frame by _get_next_pathposition() method (instead of _set_targetposition()), so I have assumed that path resetting was inevitable.

Maybe the documentation you linked could be updated to add some hints on what could trigger a path reset ?

smix8 commented 1 week ago

Closing as this is documented in a few places by now like the agent function documentation and common agent problems.