Использовать NavigationObstacles
2D- и 3D-версии узлов NavigationObstacles доступны как NavigationObstacle2D и NavigationObstacle3D соответственно.
Навигационные препятствия имеют двойное назначение, поскольку они могут влиять как на выпечку навигационной сетки, так и на уклонение агента.
При включенном
affect_navigation_meshпрепятствие будет влиять на навигационную сетку при запекании.При
avoidance_enabledпрепятствие будет влиять на агентов избегания.
Совет
Функция избегания включена по умолчанию. Если препятствие не используется для избегания, отключите enabled_avoidance для экономии производительности.
Препятствия и навигационная сетка
Навигационные препятствия, влияющие на запекание навигационной сетки.
При запекании навигационной сетки препятствия можно использовать для отбрасывания частей всей другой исходной геометрии внутри формы препятствия.
Это можно использовать, чтобы предотвратить запекание навигационных сеток в нежелательных местах, например, внутри «твердой» геометрии, таких как, толстых стен, или поверх другой геометрии, которая не должна быть включена в игровой процесс, например, крыш.
Препятствия к навигации: отбрасывание ненужной навигационной сетки.
Препятствие не добавляет геометрию в процессе запекания, а только удаляет её. Это достигается путём аннулирования всех ячеек (вокселей) с растеризованной исходной геометрией, находящихся внутри препятствия. Таким образом, его эффект и детализация формы ограничены разрешением ячеек, используемым в процессе запекания.
Более подробную информацию о запекании навигационной сетки см. Использование навигационных сеток.
Свойство affect_navigation_mesh позволяет препятствию участвовать в процессе запекания навигационной сетки. Оно будет подвергнуто или не подвергнуто анализу, как и все остальные объекты-узлы в процессе запекания навигационной сетки.
Свойство carve_navigation_mesh делает форму невосприимчивой к смещениям при запекании, например, к смещению, добавленному навигационной сеткой agent_radius. По сути, оно действует как трафарет и вырезает уже смещенную поверхность навигационной сетки. На него по-прежнему будет влиять дальнейшая постобработка процесса запекания, например, упрощение рёбер.
Форма и расположение препятствия определяются свойствами height и vertices, а также global_position препятствия. Значение по оси Y любого Vector3, используемого для вершин, игнорируется, поскольку препятствие проецируется на плоскую горизонтальную плоскость.
При запекании навигационных сеток в скриптах препятствия можно добавлять процедурно как проецируемые. Препятствия не участвуют в анализе исходной геометрии, поэтому их достаточно добавить непосредственно перед запеканием.
var obstacle_outline = PackedVector2Array([
Vector2(-50, -50),
Vector2(50, -50),
Vector2(50, 50),
Vector2(-50, 50)
])
var navigation_mesh = NavigationPolygon.new()
var source_geometry = NavigationMeshSourceGeometryData2D.new()
NavigationServer2D.parse_source_geometry_data(navigation_mesh, source_geometry, $MyTestRootNode)
var obstacle_carve: bool = true
source_geometry.add_projected_obstruction(obstacle_outline, obstacle_carve)
NavigationServer2D.bake_from_source_geometry_data(navigation_mesh, source_geometry)
Vector2[] obstacleOutline
[
new Vector2(-50, -50),
new Vector2(50, -50),
new Vector2(50, 50),
new Vector2(-50, 50),
];
var navigationMesh = new NavigationPolygon();
var sourceGeometry = new NavigationMeshSourceGeometryData2D();
NavigationServer2D.ParseSourceGeometryData(navigationMesh, sourceGeometry, GetNode<Node2D>("MyTestRootNode"));
bool obstacleCarve = true;
sourceGeometry.AddProjectedObstruction(obstacleOutline, obstacleCarve);
NavigationServer2D.BakeFromSourceGeometryData(navigationMesh, sourceGeometry);
var obstacle_outline = PackedVector3Array([
Vector3(-5, 0, -5),
Vector3(5, 0, -5),
Vector3(5, 0, 5),
Vector3(-5, 0, 5)
])
var navigation_mesh = NavigationMesh.new()
var source_geometry = NavigationMeshSourceGeometryData3D.new()
NavigationServer3D.parse_source_geometry_data(navigation_mesh, source_geometry, $MyTestRootNode)
var obstacle_elevation: float = $MyTestObstacleNode.global_position.y
var obstacle_height: float = 50.0
var obstacle_carve: bool = true
source_geometry.add_projected_obstruction(obstacle_outline, obstacle_elevation, obstacle_height, obstacle_carve)
NavigationServer3D.bake_from_source_geometry_data(navigation_mesh, source_geometry)
Vector3[] obstacleOutline =
[
new Vector3(-5, 0, -5),
new Vector3(5, 0, -5),
new Vector3(5, 0, 5),
new Vector3(-5, 0, 5),
];
var navigationMesh = new NavigationMesh();
var sourceGeometry = new NavigationMeshSourceGeometryData3D();
NavigationServer3D.ParseSourceGeometryData(navigationMesh, sourceGeometry, GetNode<Node3D>("MyTestRootNode"));
float obstacleElevation = GetNode<Node3D>("MyTestObstacleNode").GlobalPosition.Y;
float obstacleHeight = 50.0f;
bool obstacleCarve = true;
sourceGeometry.AddProjectedObstruction(obstacleOutline, obstacleElevation, obstacleHeight, obstacleCarve);
NavigationServer3D.BakeFromSourceGeometryData(navigationMesh, sourceGeometry);
Препятствия и избегание агента
Для уклонения от навигационных препятствий можно использовать как статические, так и динамические препятствия, чтобы воздействовать на контролируемые агенты уклонения.
При статическом использовании NavigationObstacles ограничивает контролируемые агенты, находящиеся вне или внутри области, определенной многоугольником.
При динамическом использовании NavigationObstacles отталкивают агентов, контролируемых уклонением, в радиусе вокруг них.
Статические препятствия для избегания
Препятствие для избегания считается статическим, если его свойство vertices заполнено массивом контуров позиций, образующих многоугольник.
Статическое препятствие, нарисованное в редакторе для блокировки или сдерживания навигационных агентов.
Статичные препятствия действуют как жесткие границы запрета на пересечение, которые можно обойти с помощью агентов, например, аналогично физическим столкновениям, но для обхода.
Статичные препятствия определяют свои границы с помощью массива
вершинконтура (позиций), а в случае 3D — с помощью дополнительного свойствавысоты.Статичные препятствия работают только для агентов, использующих режим 2D-избегания.
Статические препятствия определяют посредством порядка обхода вершин, выталкиваются ли агенты или засасываются.
Статичные препятствия не могут менять своё положение. Их можно только переместить в новое положение и перестроить заново. Поэтому статические препятствия плохо подходят для ситуаций, где положение меняется в каждом кадре, поскольку постоянное перестроение приводит к высоким потерям производительности.
Агенты не могут предсказать, где находятся статические препятствия, деформированные в другое положение. Это создаёт риск застревания агентов, если статическое препятствие деформируется на них.
При использовании 2D-обхода в 3D ось Y вершин Vector3 игнорируется. Вместо этого в качестве уровня высоты используется глобальное положение препятствия по оси Y. Агенты будут игнорировать статические препятствия в 3D, находящиеся ниже или выше них. Это автоматически определяется глобальным положением препятствия и агента по оси Y, а также их соответствующими свойствами высоты.
Динамические препятствия для избегания
Препятствие для избегания считается динамическим, если его свойство радиус больше нуля.
Динамические препятствия действуют как мягкий объект "пожалуйста, отойдите от меня", который агенты избегают, например, аналогично тому, как они избегают других агентов.
Границы динамических препятствий определяются единым
радиусомдля двухмерного круга или, в случае трехмерного обхода, формой сферы.Динамические препятствия могут менять свое положение в каждом кадре без дополнительных затрат производительности.
Динамические препятствия с заданной скоростью могут быть спрогнозированы агентами по их движению.
Динамические препятствия не являются надежным способом ограничения движения агентов в людных или узких пространствах.
Хотя статические и динамические свойства могут быть активны одновременно на одном и том же препятствии, это не рекомендуется для производительности. В идеале, когда препятствие движется, статические вершины удаляются и вместо них активируется радиус. Когда препятствие достигает нового конечного положения, оно должно постепенно увеличивать свой радиус, чтобы оттолкнуть всех остальных агентов. Создав достаточно безопасного пространства вокруг препятствия, следует снова добавить статические вершины и удалить радиус. Это помогает избежать застревания агентов во внезапно появляющемся статическом препятствии после завершения восстановления статической границы.
Подобно агентам, препятствия могут использовать битовую маску avoidance_layers. Все агенты с соответствующим битом в своей маске избегания будут избегать препятствия.
Процедурные препятствия
Новые препятствия можно создавать в скрипте без узла, используя напрямую NavigationServer.
Для создания препятствий с помощью скриптов требуется как минимум карта и позиция. Для динамического использования требуется радиус. Для статического использования требуется массив вершин.
# create a new "obstacle" and place it on the default navigation map.
var new_obstacle_rid: RID = NavigationServer2D.obstacle_create()
var default_map_rid: RID = get_world_2d().get_navigation_map()
NavigationServer2D.obstacle_set_map(new_obstacle_rid, default_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)
// Create a new "obstacle" and place it on the default navigation map.
Rid newObstacleRid = NavigationServer2D.ObstacleCreate();
Rid defaultMapRid = GetWorld2D().NavigationMap;
NavigationServer2D.ObstacleSetMap(newObstacleRid, defaultMapRid);
NavigationServer2D.ObstacleSetPosition(newObstacleRid, GlobalPosition);
// Use obstacle dynamic by increasing radius above zero.
NavigationServer2D.ObstacleSetRadius(newObstacleRid, 5.0f);
// Use obstacle static by adding a square that pushes agents out.
Vector2[] outline =
[
new Vector2(-100, -100),
new Vector2(100, -100),
new Vector2(100, 100),
new Vector2(-100, 100),
];
NavigationServer2D.ObstacleSetVertices(newObstacleRid, outline);
// Enable the obstacle.
NavigationServer2D.ObstacleSetAvoidanceEnabled(newObstacleRid, true);
# Create a new "obstacle" and place it on the default navigation map.
var new_obstacle_rid: RID = NavigationServer3D.obstacle_create()
var default_map_rid: RID = get_world_3d().get_navigation_map()
NavigationServer3D.obstacle_set_map(new_obstacle_rid, default_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)
// Create a new "obstacle" and place it on the default navigation map.
Rid newObstacleRid = NavigationServer3D.ObstacleCreate();
Rid defaultMapRid = GetWorld3D().NavigationMap;
NavigationServer3D.ObstacleSetMap(newObstacleRid, defaultMapRid);
NavigationServer3D.ObstacleSetPosition(newObstacleRid, GlobalPosition);
// Use obstacle dynamic by increasing radius above zero.
NavigationServer3D.ObstacleSetRadius(newObstacleRid, 5.0f);
// Use obstacle static by adding a square that pushes agents out.
Vector3[] outline =
[
new Vector3(-5, 0, -5),
new Vector3(5, 0, -5),
new Vector3(5, 0, 5),
new Vector3(-5, 0, 5),
];
NavigationServer3D.ObstacleSetVertices(newObstacleRid, outline);
// Set the obstacle height on the y-axis.
NavigationServer3D.ObstacleSetHeight(newObstacleRid, 1.0f);
// Enable the obstacle.
NavigationServer3D.ObstacleSetAvoidanceEnabled(newObstacleRid, true);