Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

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 in 2D using the default navigation map
var default_2d_map_rid: RID = get_world_2d().get_navigation_map()
var start_position: Vector2 = Vector2(0.0, 0.0)
var target_position: Vector2 = Vector2(5.0, 0.0)
var path: PackedVector2Array = NavigationServer2D.map_get_path(
    default_2d_map_rid,
    start_position,
    target_position,
    true
)
extends Node3D
# basic query for a navigation path in 3D using the default navigation map
var default_3d_map_rid: RID = get_world_3d().get_navigation_map()
var start_position: Vector3 = Vector3(0.0, 0.0, 0.0)
var target_position: Vector3 = Vector3(5.0, 0.0, 3.0)
var path: PackedVector3Array = NavigationServer3D.map_get_path(
    default_3d_map_rid,
    start_position,
    target_position,
    true
)

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)