Up to date

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

使用 NavigationObstacle

NavigationObstacle 即导航障碍物,可以用作静态或动态障碍物,影响由避障系统控制的代理。

  • When used statically NavigationObstacles constrain avoidance controlled agents outside or inside a polygon defined area.

  • When used dynamically NavigationObstacles push away avoidance controlled agents in a radius around them.

2D 和 3D 版本的 NavigationObstacle 节点分别为 NavigationObstacle2DNavigationObstacle3D

备注

NavigationObstacles do not change or influence the pathfinding in any way. NavigationObstacles only affect the avoidance velocities of agents controlled by avoidance.

静态障碍物

A NavigationObstacle is considered static when its vertices property is populated with an outline array of positions to form a polygon.

../../_images/nav_static_obstacle_build.gif
  • Static obstacles act as hard do-not-cross boundaries for avoidance using agents, e.g. similar to physics collision but for avoidance.

  • Static obstacles define their boundaries with an array of outline vertices (positions), and in case of 3D with an additional height property.

  • Static obstacles only work for agents that use the 2D avoidance mode.

  • Static obstacles define through winding order of the vertices if agents are pushed out or sucked in.

  • Static obstacles can not change their position. They can only be warped to a new position and rebuild from scratch. Static obstacles as a result are ill-suited for usages where the position is changed every frame as the constant rebuild has a high performance cost.

  • Static obstacles that are warped to another position can not be predicted by agents. This creates the risk of getting agents stuck should a static obstacle be warped on top of agents.

When the 2D avoidance is used in 3D the y-axis of Vector3 vertices is ignored. Instead, the global y-axis position of the obstacle is used as the elevation level. Agents will ignore static obstacles in 3D that are below or above them. This is automatically determined by global y-axis position of both obstacle and agent as the elevation level as well as their respective height properties.

动态障碍物

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)