Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Використання NavigationPaths
Отримання NavigationPath
Шляхи навігації можна запитувати безпосередньо з NavigationServer і не потребують додаткових вузлів чи об’єктів, якщо навігаційна карта має навігаційну сітку для роботи.
Щоб отримати двовимірний шлях, використовуйте NavigationServer2D.map_get_path(map, from, to, optimize, navigation_layers).
Щоб отримати тривимірний шлях, використовуйте NavigationServer3D.map_get_path(map, from, to, optimize, navigation_layers).
Більше настроюваних запитів шляху навігації, які потребують додаткового налаштування, див. Використання NavigationPath QueryObjects.
Одним із обов’язкових параметрів для запиту є RID навігаційної карти. Для кожного ігрового світу автоматично створюється стандартна навігаційна карта. Стандартні навігаційні карти можна отримати за допомогою get_world_2d().get_navigation_map() з будь-якого вузла-спадкоємця Node2D або get_world_3d().get_navigation_map() з будь-якого вузла-спадкоємця Node3D. Другий і третій параметри – це початкова позиція та цільова позиція як Vector2 для 2D або Vector3 для 3D.
Якщо параметр optimized має значення true, позиції шляху будуть скорочені вздовж кутів багатокутників за допомогою додаткового проходу алгоритму воронки. Це добре працює для вільного переміщення по навігаційній сітці з багатокутниками різного розміру, оскільки шлях буде обіймати кути вздовж коридору багатокутника, знайденого алгоритмом A*. З маленькими клітинками алгоритм A* створює дуже вузький коридор воронки, який може створювати потворні кутові шляхи при використанні з сітками.
Якщо параметр optimized має значення false, позиції шляху будуть розміщені в центрі кожного краю багатокутника. Це добре працює для чистого руху сітки на навігаційних сітках з багатокутниками однакового розміру, оскільки шлях проходитиме через центр комірок сітки. За межами сітки через багатокутники, які часто охоплюють великі відкриті території з одним довгим краєм, це може створити шляхи з непотрібними довгими об’їздами.
extends Node2D
# Basic query for a navigation path using the default navigation map.
func get_navigation_path(p_start_position: Vector2, p_target_position: Vector2) -> PackedVector2Array:
if not is_inside_tree():
return PackedVector2Array()
var default_map_rid: RID = get_world_2d().get_navigation_map()
var path: PackedVector2Array = NavigationServer2D.map_get_path(
default_map_rid,
p_start_position,
p_target_position,
true
)
return path
using Godot;
using System;
public partial class MyNode2D : Node2D
{
// Basic query for a navigation path using the default navigation map.
private Vector2[] GetNavigationPath(Vector2 startPosition, Vector2 targetPosition)
{
if (!IsInsideTree())
{
return Array.Empty<Vector2>();
}
Rid defaultMapRid = GetWorld2D().NavigationMap;
Vector2[] path = NavigationServer2D.MapGetPath(
defaultMapRid,
startPosition,
targetPosition,
true
);
return path;
}
}
extends Node3D
# Basic query for a navigation path using the default navigation map.
func get_navigation_path(p_start_position: Vector3, p_target_position: Vector3) -> PackedVector3Array:
if not is_inside_tree():
return PackedVector3Array()
var default_map_rid: RID = get_world_3d().get_navigation_map()
var path: PackedVector3Array = NavigationServer3D.map_get_path(
default_map_rid,
p_start_position,
p_target_position,
true
)
return path
using Godot;
using System;
public partial class MyNode3D : Node3D
{
// Basic query for a navigation path using the default navigation map.
private Vector3[] GetNavigationPath(Vector3 startPosition, Vector3 targetPosition)
{
if (!IsInsideTree())
{
return Array.Empty<Vector3>();
}
Rid defaultMapRid = GetWorld3D().NavigationMap;
Vector3[] path = NavigationServer3D.MapGetPath(
defaultMapRid,
startPosition,
targetPosition,
true
);
return path;
}
}
Повернений шлях NavigationServer буде PackedVector2Array для 2D або PackedVector3Array для 3D. Це лише оптимізований для пам’яті Масив векторних позицій. Гарантовано, що всі вектори позиції всередині масиву знаходяться в NavigationPolygon або NavigationMesh. Масив шляхів, якщо він не порожній, має позицію навігаційної сітки, найближчу до початкової позиції в позиції першого індексу path[0]. Найближча доступна позиція навігаційної сітки до цільової позиції – це позиція останнього індексу path[path.size()-1]. Усі індекси між ними є точками шляху, якими актор має слідувати, щоб досягти мети, не виходячи з навігаційної сітки.
Примітка
Якщо цільова позиція знаходиться в іншій навігаційній сітці, яка не об’єднана або не з’єднана, шлях навігації приведе до найближчої можливої позиції на навігаційній сітці початкової позиції.
Наступний скрипт переміщує вузол-спадкоємець Node3D уздовж навігаційного шляху, використовуючи навігаційну карту за замовчуванням, встановлюючи цільову позицію за допомогою set_movement_target().
@onready var default_3d_map_rid: RID = get_world_3d().get_navigation_map()
var movement_speed: float = 4.0
var movement_delta: float
var path_point_margin: float = 0.5
var current_path_index: int = 0
var current_path_point: Vector3
var current_path: PackedVector3Array
func set_movement_target(target_position: Vector3):
var start_position: Vector3 = global_transform.origin
current_path = NavigationServer3D.map_get_path(
default_3d_map_rid,
start_position,
target_position,
true
)
if not current_path.is_empty():
current_path_index = 0
current_path_point = current_path[0]
func _physics_process(delta):
if current_path.is_empty():
return
movement_delta = movement_speed * delta
if global_transform.origin.distance_to(current_path_point) <= path_point_margin:
current_path_index += 1
if current_path_index >= current_path.size():
current_path = []
current_path_index = 0
current_path_point = global_transform.origin
return
current_path_point = current_path[current_path_index]
var new_velocity: Vector3 = global_transform.origin.direction_to(current_path_point) * movement_delta
global_transform.origin = global_transform.origin.move_toward(global_transform.origin + new_velocity, movement_delta)
using Godot;
public partial class MyNode3D : Node3D
{
private Rid _default3DMapRid;
private float _movementSpeed = 4.0f;
private float _movementDelta;
private float _pathPointMargin = 0.5f;
private int _currentPathIndex = 0;
private Vector3 _currentPathPoint;
private Vector3[] _currentPath;
public override void _Ready()
{
_default3DMapRid = GetWorld3D().NavigationMap;
}
private void SetMovementTarget(Vector3 targetPosition)
{
Vector3 startPosition = GlobalTransform.Origin;
_currentPath = NavigationServer3D.MapGetPath(_default3DMapRid, startPosition, targetPosition, true);
if (!_currentPath.IsEmpty())
{
_currentPathIndex = 0;
_currentPathPoint = _currentPath[0];
}
}
public override void _PhysicsProcess(double delta)
{
if (_currentPath.IsEmpty())
{
return;
}
_movementDelta = _movementSpeed * (float)delta;
if (GlobalTransform.Origin.DistanceTo(_currentPathPoint) <= _pathPointMargin)
{
_currentPathIndex += 1;
if (_currentPathIndex >= _currentPath.Length)
{
_currentPath = Array.Empty<Vector3>();
_currentPathIndex = 0;
_currentPathPoint = GlobalTransform.Origin;
return;
}
}
_currentPathPoint = _currentPath[_currentPathIndex];
Vector3 newVelocity = GlobalTransform.Origin.DirectionTo(_currentPathPoint) * _movementDelta;
var globalTransform = GlobalTransform;
globalTransform.Origin = globalTransform.Origin.MoveToward(globalTransform.Origin + newVelocity, _movementDelta);
GlobalTransform = globalTransform;
}
}