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...
Verwenden von NavigationPaths
Ermittlung eines NavigationPaths
Navigationspfade können direkt vom NavigationServer abgefragt werden und benötigen keine zusätzlichen Nodes oder Objekte, solange die Navigations-Map über ein Navigations-Mesh verfügt, mit dem gearbeitet werden kann.
Um einen 2D-Pfad zu erhalten, verwenden Sie NavigationServer2D.map_get_path(map, from, to, optimize, navigation_layers).
Um einen 3D-Pfad zu erhalten, verwenden Sie NavigationServer3D.map_get_path(map, from, to, optimize, navigation_layers).
Für weitere anpassbare Navigationspfad-Abfragen, die zusätzliche Einstellungen erfordern, siehe Verwendung von NavigationPathQueryObjects.
Einer der erforderlichen Parameter für die Abfrage ist die RID der Navigations-Map. Jede Spielwelt hat eine automatisch erstellte Default-Navigations-Map. Die Default-Navigations-Maps können mit get_world_2d().get_navigation_map() von jedem von Node2D-erbenden Node oder get_world_3d().get_navigation_map() von jedem von Node3D-erbenden Node abgefragt werden. Der zweite und dritte Parameter sind die Startposition und die Zielposition als Vector2 für 2D oder Vector3 für 3D.
Wenn der Parameter optimized auf true steht, werden die Pfadpositionen entlang der Polygonecken mit einem zusätzlichen Trichteralgorithmus-Durchlauf verkürzt. Dies funktioniert gut für die freie Bewegung auf Meshes mit ungleich großen Polygonen, da der Pfad sich um die Ecken entlang des vom A*-Algorithmus gefundenen Polygonkorridors schmiegt. Bei kleinen Zellen erzeugt der A*-Algorithmus einen sehr schmalen Trichterkorridor, der bei der Verwendung mit Rastern hässliche Eckpfade erzeugen kann.
Wenn der Parameter optimized auf false gesetzt ist, werden die Pfadpositionen in der Mitte jeder Polygonkante platziert. Dies funktioniert gut bei reinen Rasterbewegungen auf Meshes mit gleichgroßen Polygonen, da der Pfad durch die Mitte der Rasterzellen verläuft. Außerhalb von Rastern kann dies aufgrund der Tatsache, dass Polygone oft große offene Flächen mit einer einzigen langen Kante abdecken, Pfade mit unnötig langen Umwegen erzeugen.
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;
}
}
Ein vom NavigationServer zurückgegebener Pfad ist ein PackedVector2Array für 2D oder ein PackedVector3Array für 3D. Diese sind lediglich ein speicheroptimiertes Array von Vektorpositionen. Alle Positionsvektoren innerhalb des Arrays befinden sich garantiert innerhalb eines NavigationPolygons oder NavigationMesh. Das Pfad-Array enthält, wenn es nicht leer ist, die Position des Navigations-Meshes, die der Startposition am nächsten liegt, an der ersten path[0]-Position. Die der Zielposition nächstgelegene verfügbare Position des Navigation Mesh ist die Position mit dem letzten Index path[path.size()-1]. Alle Indizes dazwischen sind die Pfadpunkte, denen ein Akteur folgen sollte, um das Ziel zu erreichen, ohne das Navigations-Mesh zu verlassen.
Bemerkung
Befindet sich die Zielposition auf einem anderen Navigations-Mesh, das nicht zusammengeführt oder verbunden ist, führt der Navigationspfad zur nächstmöglichen Position auf dem Navigations-Mesh der Startposition.
Das folgende Skript verschiebt einen von Node3D geerbten Node entlang eines Navigationspfades unter Verwendung der Default-Navigations-Map, indem es die Zielposition mit set_movement_target() setzt.
@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;
}
}