使用 NavigationPath
获取 NavigationPath
导航路径可以直接从NavigationServer查询,并且不需要任何其他节点或对象,只要导航地图具有可使用的导航网格即可。
要获取 2D 路径,请使用 NavigationServer2D.map_get_path(地图, 起点, 终点, 优化, 导航层)
。
要获取 3D 路径,请使用 NavigationServer3D.map_get_path(地图, 起点, 终点, 优化, 导航层)
。
有关需要额外设定的更多可自定义导览路径查询,请参阅 使用 NavigationPathQueryObject。
查询所需的参数之一是导航地图的RID。每个游戏世界都有一个自动创建的默认导航地图。默认导航地图可以使用 get_world_2d().get_navigation_map()
从任何Node2D继承节点检索,也可以使用 get_world_3d().get_navigation_map()
从任意Node3D继承节点检索。第二和第三参数是起始位置和目标位置,作为2D的Vector2或3D的Vector3。
如果 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返回的 path
将是2D的 PackedVector2Array
或3D的 PackedVector3Array
。这些只是一个经过内存优化的矢量位置 Array
。阵列内的所有位置矢量都保证位于NavigationPolygon或NavigationMesh内。如果路径数组不是空的,则其导航网格位置最靠近第一个索引 path[0]
位置处的起始位置。离目标位置最近的可用导航网格位置是最后一个索引 path[path.size()-1]
位置。之间的所有索引都是参与者在不离开导航网格的情况下到达目标所应遵循的路径点。
备注
如果目标位置位于未合并或连接的不同导览网格上,则导览路径将通往起始位置导览网格上最接近的可能位置。
以下脚本透过使用 set_movement_target()
设定目标位置,使用预设导览地图沿着导览路径移动Node3D继承节点。
@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;
}
}