godot icon indicating copy to clipboard operation
godot copied to clipboard

Creating obstacles through NavigationServer2D does not work

Open nezvers opened this issue 1 year ago • 1 comments

Tested versions

Reproducible 4.3

System information

Godot v4.3.stable - Windows 10.0.19045 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 2070 SUPER (NVIDIA; 31.0.15.5186) - Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz (8 Threads)

Issue description

# for reproduction using drawn line for vertices
extends Line2D

## TileMapLayer for creating obstacle tiles
@export var tilemap_layer:TileMapLayer
## Obstacle's Navigation layer
@export_flags_2d_navigation var obstacle_layer:int

var obstacle_rid:RID

func _ready() -> void:
	var _navigation_rid:RID = tilemap_layer.get_navigation_map()
	
	obstacle_rid = NavigationServer2D.obstacle_create()
	NavigationServer2D.obstacle_set_map(obstacle_rid, _navigation_rid)
	NavigationServer2D.obstacle_set_avoidance_layers(obstacle_rid, obstacle_layer)
	NavigationServer2D.obstacle_set_position(obstacle_rid, global_position)
	# use drawn points for vertices (Counter-clock for repel as documented)
	NavigationServer2D.obstacle_set_vertices(obstacle_rid, points)
	NavigationServer2D.obstacle_set_avoidance_enabled(obstacle_rid, true)
	NavigationServer2D.obstacle_set_paused(obstacle_rid, false)
	
	NavigationServer2D.map_force_update(_navigation_rid)

func _exit_tree() -> void:
	NavigationServer2D.free_rid(obstacle_rid)

NavigationServer2D returns that it has registered obstacle RID, but debug drawing doesn't look like something was changed. NavigationAgent2D still gives a path through the obstacle place with enabled avoidance.

Steps to reproduce

  • create an obstacle with GDscript calling NavigationServer2D
  • use counter-clock vertices
  • set common avoidance_layer flags
  • enable avoidance on NavigationAgent2D
  • walk through zone that's supposed to be navigation obstacle

Minimal reproduction project (MRP)

navigation_obstacles.zip

nezvers avatar Oct 07 '24 16:10 nezvers

NavigationServer2D returns that it has registered obstacle RID, but debug drawing doesn't look like something was changed.

Debug is drawn by nodes. If you dont use nodes but the server directly you have no debug visuals and need to draw your own debug.

NavigationAgent2D still gives a path through the obstacle place with enabled avoidance.

Avoidance and pathfinding are different systems. RVO Avoidance works with velocities, it has nothing to do with the navigation mesh surface based pathfinding.

The obstacle that was created here would affect the avoidance velocity, it will do nothing for pathfinding. The only thing that affects pathfinding is the navigation mesh surface. The obstacle shape can be baked to the navigation mesh surface when affect_navigation_mesh=true is enabled but it still needs to be baked with the navigation mesh like any other object that should affect the pathfinding.

smix8 avatar Oct 07 '24 19:10 smix8

That sounds wrong.

  • Documentation says Creates a new navigation obstacle.
    • Nothing about avoidance or pathfinding or only for affecting velocity.
  • How velocity can help if the path goes through the obstacle?

If NavigationServer doesn't create an actual obstacle than what does?

nezvers avatar Oct 08 '24 07:10 nezvers

This also not work on Linux 4.3 Stable.

If use NavigationServer2D.obstacle_set_map E.g.:

    new_obstacle_rid= NavigationServer2D.obstacle_create()

    NavigationServer2D.obstacle_set_position(new_obstacle_rid, Vector2(20, 20))
    NavigationServer2D.obstacle_set_radius(new_obstacle_rid, 0.0)
    var outline = PackedVector2Array([Vector2(-100, -100), Vector2(150, -100), Vector2(100, 100), Vector2(-100, 100)])
    NavigationServer2D.obstacle_set_vertices(new_obstacle_rid, outline)

    NavigationServer2D.obstacle_set_avoidance_enabled(new_obstacle_rid, true)
    NavigationServer2D.obstacle_set_map(new_obstacle_rid, map_id)

The return of 'NavigationServer2D.map_get_obstacles' will contains this obstacle id,

but it does not work with PATH FINDING.

Instead.

If I use 'add_obstruction_outline' of the same points to the source_geometry and it would work

E.g.:

    var outline = PackedVector2Array([Vector2(-100, -100), Vector2(150, -100), Vector2(100, 100), Vector2(-100, 100)])
    source_geometry.add_obstruction_outline(outline)
    NavigationServer2D.bake_from_source_geometry_data_async(nav_polygon, source_geometry, callback_baking)

Also, Using the obstacle Node NavigationObstacle2D with NavigationRegion2D works.

rakzin avatar Oct 26 '24 06:10 rakzin

obs 0 Screenshot from 2024-10-26 14-46-49 obs 1 Screenshot from 2024-10-26 14-47-09

min_project bug_nav_obstacle.tar.gz

rakzin avatar Oct 26 '24 06:10 rakzin

A further investigation found that:

  1. create obs0 and then create obs1, obs0 not valid , which obs0 should be valid Screenshot from 2024-10-26 16-26-36

  2. remove obs1, the obs0 became valid Screenshot from 2024-10-26 16-27-39

  3. remove obs0, the obs0 remains valid, which obs0 should be invalid Screenshot from 2024-10-26 16-27-52

create / remove obs1 just use bake_from_source_geometry_data_async, but call this when creating obs0 seems takes no effect

rakzin avatar Oct 26 '24 08:10 rakzin

Closing as this was already explained in my original answer.

How obstacles and navmesh work is documented at length in the official documentation in multiple places. There are 2 dedicated pages for navmesh and obstacles alone that can be found here https://docs.godotengine.org/en/latest/tutorials/navigation/navigation_using_navigationmeshes.html and here https://docs.godotengine.org/en/latest/tutorials/navigation/navigation_using_navigationobstacles.html explaining it further. If you use the server api instead of nodes you also need to bake your obstacles this way to the navmesh. The documentation has examples for this.

smix8 avatar Dec 18 '24 03:12 smix8