Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

使用 NavigationObstacle

導覽障礙物可以用作靜態或動態障礙物來影響迴避控制代理。

  • 當靜態使用時,導覽障礙會限制多邊形定義區域外部或內部的迴避控制代理。

  • 當動態使用時,導覽障礙會推開其周圍半徑範圍內的迴避控制代理。

2D 和 3D 版本的 NavigationObstacles 節點分別可用作:ref:NavigationObstacle2D<class_NavigationObstacle2D> 和:ref:NavigationObstacle3D<class_NavigationObstacle3D>

備註

導覽障礙不會以任何方式改變或影響尋路。導覽障礙僅影響受迴避控制的代理的迴避速度。

靜態形體。

當 NavigationObstacle 的「vertices」屬性填入有位置的輪廓陣列以形成多邊形時,該 NavigationObstacle 被認為是靜態的。

../../_images/nav_static_obstacle_build.gif
  • 靜態障礙物充當硬性請勿跨越邊界,以使用代理進行迴避,例如類似於物理碰撞,但用於迴避。

  • 靜態障礙物使用一系列輪廓「頂點」(位置)定義其邊界,如果是 3D,則具有附加的「高度」屬性。

  • 靜態障礙物僅適用於使用 2D 迴避模式的代理。

  • 如果代理人被推出或吸入,靜態障礙物透過頂點的纏繞順序來定義。

  • 靜態障礙物不能改變其位置。它們只能扭曲到新的位置並從頭開始重建。因此,靜態障礙物不適合每影格位置都會改變的用途,因為不斷重建會產生很高的效能成本。

  • 代理無法預測扭曲到另一個位置的靜態障礙物。如果靜態障礙物扭曲到代理頂部,這就會產生代理被卡住的風險。

當在 3D 中使用 2D 迴避時,Vector3 頂點的 y 軸將被忽略。相反,障礙物的全局 y 軸位置用作海拔高度。代理將忽略 3D 中低於或高於其的靜態障礙物。這是由障礙物和代理的全局 y 軸位置自動確定為海拔高度以及它們各自的高度屬性。

動態性

NavigationObstacle 的 radius 屬性大於零時就會被認為是動態障礙物。

  • 對於啟用了避障的代理而言,動態障礙物就是一個“請離我遠點”的物件,類似於它們自己躲避其他代理的行為。

  • 動態障礙物使用 radius 半徑來定義邊界,2D 中是圓形,3D 中是球形。

  • 動態障礙物每一影格都可以改變位置,不會有額外的性能開銷。

  • 動態障礙物設定速度後,其他代理就能夠預測移動。

  • 動態障礙物不適合用來將代理限制在擁擠、狹窄的空間中。

雖然障礙物可以同時啟動靜態和動態屬性,但是出於性能的考慮不建議這麼做。理想情況下,障礙物移動時,應該把靜態頂點移除、啟動半徑。障礙物到達目的地後,應該逐步增大半徑,將其他代理推開。在障礙物的周圍創造出足夠大的安全區域後,就應該把靜態頂點新增回來、移除半徑。這樣就能夠避免重建靜態邊界後,代理因為靜態障礙物的突然出現而被卡住。

和代理類似,障礙物也能夠使用 avoidance_layers 位元遮罩。自身的避障遮罩中與之存在配對位元的代理都會躲避這個障礙物。

程式性天空。

可以不借助節點,直接在 NavigationServer 上新建障礙物。

使用腳本建立的障礙物至少需要有一個 map 和一個 position。動態障礙物還需要 radius。靜態障礙物還需要 vertices 屬性。

# For 2D

# create a new "obstacle" and place it on the default navigation map.
var new_obstacle_rid: RID = NavigationServer2D.obstacle_create()
var default_2d_map_rid: RID = get_world_2d().get_navigation_map()

NavigationServer2D.obstacle_set_map(new_obstacle_rid, default_2d_map_rid)
NavigationServer2D.obstacle_set_position(new_obstacle_rid, global_position)

# Use obstacle dynamic by increasing radius above zero.
NavigationServer2D.obstacle_set_radius(new_obstacle_rid, 5.0)

# Use obstacle static by adding a square that pushes agents out.
var outline = PackedVector2Array([Vector2(-100, -100), Vector2(100, -100), Vector2(100, 100), Vector2(-100, 100)])
NavigationServer2D.obstacle_set_vertices(new_obstacle_rid, outline)

# Enable the obstacle.
NavigationServer2D.obstacle_set_avoidance_enabled(new_obstacle_rid, true)
# For 3D

# Create a new "obstacle" and place it on the default navigation map.
var new_obstacle_rid: RID = NavigationServer3D.obstacle_create()
var default_3d_map_rid: RID = get_world_3d().get_navigation_map()

NavigationServer3D.obstacle_set_map(new_obstacle_rid, default_3d_map_rid)
NavigationServer3D.obstacle_set_position(new_obstacle_rid, global_position)

# Use obstacle dynamic by increasing radius above zero.
NavigationServer3D.obstacle_set_radius(new_obstacle_rid, 0.5)

# Use obstacle static by adding a square that pushes agents out.
var outline = PackedVector3Array([Vector3(-5, 0, -5), Vector3(5, 0, -5), Vector3(5, 0, 5), Vector3(-5, 0, 5)])
NavigationServer3D.obstacle_set_vertices(new_obstacle_rid, outline)
# Set the obstacle height on the y-axis.
NavigationServer3D.obstacle_set_height(new_obstacle_rid, 1.0)

# Enable the obstacle.
NavigationServer3D.obstacle_set_avoidance_enabled(new_obstacle_rid, true)