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...
Usando NavigationPaths
Obtendo um NavigationPath
Os caminhos de navegação podem ser consultados diretamente do NavigationServer e não exigem nenhum nó ou objeto adicional, desde que o mapa de navegação tenha uma malha de navegação com a qual trabalhar.
Para obter um caminho 2D, use NavigationServer2D.map_get_path(map, from, to, optimize, navigation_layers).
Para obter um caminho 3D, use NavigationServer3D.map_get_path(map, from, to, optimize, navigation_layers).
Para consultas de caminho de navegação mais customizáveis que exigem configuração adicional, consulte Usando NavigationPathQueryObjects.
Um dos parâmetros obrigatórios para a consulta é o RID do mapa de navegação. Cada mundo do jogo possui um mapa de navegação padrão criado automaticamente. Os mapas de navegação padrão podem ser recuperados com get_world_2d().get_navigation_map() a partir de qualquer nó que herde de Node2D ou get_world_3d().get_navigation_map() a partir de qualquer nó que herde de Node3D. O segundo e o terceiro parâmetros são a posição inicial e a posição de destino como Vector2 para 2D ou Vector3 para 3D.
Se o parâmetro optimized for true, as posições do caminho serão encurtadas ao longo dos cantos dos polígonos com uma etapa adicional do algoritmo de funil (funnel algorithm). Isso funciona bem para movimento livre em malhas de navegação com polígonos de tamanhos desiguais, pois o caminho contornará os cantos ao longo do corredor de polígonos encontrado pelo algoritmo A*. Com células pequenas, o algoritmo A* cria um corredor de funil muito estreito que pode gerar caminhos de canto feios quando usado com grades.
Se o parâmetro optimized for false, as posições do caminho serão colocadas no centro de cada aresta do polígono. Isso funciona bem para movimento puro em grade em malhas de navegação com polígonos de tamanhos iguais, pois o caminho passará pelo centro das células da grade. Fora das grades, devido ao fato de os polígonos frequentemente cobrirem grandes áreas abertas com uma única aresta longa, isso pode criar caminhos com desvios longos e desnecessários.
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;
}
}
Um path retornado pelo NavigationServer será um PackedVector2Array para 2D ou um PackedVector3Array para 3D. Estes são apenas um Array otimizado em memória de posições vetoriais. Todos os vetores de posição dentro do array têm a garantia de estarem dentro de um NavigationPolygon ou NavigationMesh. O array do caminho, se não estiver vazio, possui a posição da malha de navegação mais próxima da posição inicial no primeiro índice path[0]. A posição da malha de navegação disponível mais próxima da posição de destino está no último índice path[path.size()-1]. Todos os índices intermediários são os pontos do caminho que um ator deve seguir para alcançar o destino sem sair da malha de navegação.
Nota
Se a posição de destino estiver em uma malha de navegação diferente que não esteja mesclada ou conectada, o caminho de navegação levará à posição mais próxima possível na malha de navegação da posição inicial.
O script a seguir move um nó que herda de Node3D ao longo de um caminho de navegação usando o mapa de navegação padrão ao definir a posição de destino com 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;
}
}