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 NavigationAgents¶
NavigationsAgents sind Hilfs-Nodes, die Funktionalität für Wegfindung, Wegverfolgung und Agentenvermeidung für einen von Node2D/3D erbenden Parent-Node kombinieren. Sie erleichtern Anfängern gemeinsame Aufrufe der NavigationServer-API im Auftrag des übergeordneten Node-Akteurs auf bequemere Weise.
2D und 3D-Versionen von NavigationAgents sind als NavigationAgent2D bzw. NavigationAgent3D verfügbar.
Neue NavigationAgent-Nodes werden automatisch der Standard-Navigations-Map auf der World2D/World3D hinzugefügt.
NavigationsAgent Nodes sind optional und keine zwingende Voraussetzung für die Nutzung des Navigationssystems. Ihre gesamte Funktionalität kann durch Skripte und direkte Aufrufe zur NavigationServer API ersetzt werden.
NavigationAgent Wegfindung¶
NavigationAgents fragen einen neuen Navigationspfad auf ihrer aktuellen Navigations-Map ab, wenn ihre target_position
auf eine globale Position gesetzt wird.
Das Ergebnis der Wegfindung kann mit den folgenden Propertys beeinflusst werden.
Die Bitmaske
navigation_layers
kann verwendet werden, um die Navigations-Meshes einzuschränken, die der Agent verwenden kann.Der
Wegfindung-Algorithmus
steuert, wie die Wegfindung durch die Polygone des Navigation-Meshs bei der Wegfindung abläuft.path_postprocessing
legt fest, ob oder wie der rohe Pfadkorridor, der durch die Wegfindung gefunden wurde, verändert wird, bevor er zurückgegeben wird.Die
path_metadata_flags
ermöglichen das Sammeln zusätzlicher Metadaten des Pfadpunktes, die vom Pfad zurückgegeben werden.
Warnung
Durch die Deaktivierung von Pfad-Meta-Flags werden die entsprechenden Signalemissionen auf dem Agenten deaktiviert.
NavigationAgent Wegverfolgung¶
Nachdem eine Zielposition
für den Agenten festgelegt wurde, kann die nächste Position, die auf dem Pfad zu verfolgen ist, mit der Funktion get_next_path_position()
ermittelt werden.
Sobald die nächste Pfadposition empfangen wurde, bewegen Sie den übergeordneten Node des Agenten mit Ihrem eigenen Bewegungscode zu dieser Pfadposition.
Bemerkung
Das Navigationssystem verschiebt niemals den übergeordneten Node eines NavigationAgent. Die Bewegung liegt vollständig in den Händen der Benutzer und ihrer benutzerdefinierten Skripte.
NavigationAgents haben ihre eigene interne Logik, um mit dem aktuellen Pfad fortzufahren und Aktualisierungen anzufordern.
Die Funktion get_next_path_position()
ist für die Aktualisierung vieler interner Zustände und Propertys des Agenten verantwortlich. Die Funktion sollte wiederholt einmal in jedem physics_process
aufgerufen werden, bis is_navigation_finished()
mitteilt, dass der Pfad beendet ist. Die Funktion sollte nicht aufgerufen werden, nachdem die Zielposition oder das Pfadende erreicht wurde, da es den Agenten aufgrund der wiederholten Pfadaktualisierungen zum Jittern bringen kann. Prüfen Sie immer sehr früh im Skript mit is_navigation_finished()
, ob der Pfad bereits beendet ist.
Die folgenden Propertys beeinflussen das Wegverfolgungsverhalten.
path_desired_distance
definiert die Distanz, um die der Agent seinen internen Pfadindex zur nächsten Pfadposition vorrückt.target_desired_distance
definiert die Entfernung, für die der Agent die Zielposition erreicht und den Pfad als beendet ansieht.path_max_distance
definiert, wann ein Agent einen neuen Pfad anfordert, weil er sich zu weit vom aktuellen Pfadpunktsegment entfernt hat.
Die wichtigen Aktualisierungen werden alle mit der Funktion get_next_path_position()
ausgelöst, wenn sie in _physics_process()
aufgerufen wird.
NavigationAgents können mit process
verwendet werden, sind aber immer noch auf eine einzige Aktualisierung beschränkt, die in physics_process
stattfindet.
Skriptbeispiele für verschiedene Nodes, die häufig mit NavigationAgents verwendet werden, finden Sie weiter unten.
Häufige Probleme bei der Wegverfolgung¶
Beim Schreiben von Skripten für Agentenbewegungen gibt es einige häufige Benutzerprobleme und wichtige Hinweise zu beachten.
- Der Pfad wird leer zurückgegeben
Wenn ein Agent einen Pfad vor der Synchronisation der Navigations-Map abfragt, z.B. in einer
_ready()
Funktion, könnte der Pfad leer zurückkommen. In diesem Fall wird die Funktionget_next_path_position()
die gleiche Position wie der übergeordnete Node des Agenten zurückgeben und der Agent wird das Ende des Pfades als erreicht betrachten. Dies kann durch einen verzögerten Aufruf oder einen Callback behoben werden, z.B. durch Warten auf das Signal "Navigations-Map geändert".
- Der Agent zappelt zwischen zwei Positionen
Dies wird in der Regel durch sehr häufige Pfadaktualisierungen in jedem einzelnen Frame verursacht, entweder absichtlich oder aus Versehen (z.B. wenn die maximale Pfaddistanz zu kurz eingestellt ist). Die Wegfindung muss die nächstgelegene Position im Mesh finden, die für die Navigation gültig ist. Wird bei jedem Einzelbild ein neuer Pfad angefordert, kann es passieren, dass die ersten Pfadpositionen ständig vor und hinter der aktuellen Position des Agenten wechseln, so dass dieser zwischen den beiden Positionen hin und her zappelt.
- Der Agent bewegt sich manchmal rückwärts
Wenn sich ein Agent sehr schnell bewegt, kann es passieren, dass er über den path_desired_distance-Check hinausschießt, ohne jemals den Pfadindex zu erhöhen. Dies kann dazu führen, dass der Agent zu dem Wegpunkt zurückgeht, der nun hinter ihm liegt, bis er die Distanzprüfung besteht, um den Pfadindex zu erhöhen. Erhöhen Sie die gewünschten Entfernungen entsprechend Ihrer Agentengeschwindigkeit und Aktualisierungsrate, um dieses Problem zu beheben, und sorgen Sie für ein ausgewogeneres Mesh-Polygon-Layout mit nicht zu vielen Polygonkanten, die auf engem Raum zusammengepfercht sind.
- Der Agent schaut manchmal für die Dauer eines Frames rückwärts
Ähnlich wie bei Agenten, die zwischen zwei Positionen zappeln, wird dies normalerweise durch sehr häufige Pfadaktualisierungen in jedem einzelnen Frame verursacht. Abhängig vom Layout des Navigations-Meshs und insbesondere wenn ein Agent direkt über einer Kante oder einer Kantenverbindung des Navigations-Meshs platziert ist, kann es vorkommen, dass die Pfadpositionen etwas "hinter" der aktuellen Ausrichtung des Agenten liegen. Dies geschieht aufgrund von Präzisionsproblemen und kann nicht immer vermieden werden. Dies ist in der Regel nur dann ein sichtbares Problem, wenn die Akteure sofort in Richtung der aktuellen Pfadposition gedreht werden.
NavigationAgent-Vermeidung¶
In diesem Abschnitt wird erklärt, wie Sie die Navigationsvermeidung für NavigationAgents nutzen können.
Damit NavigationAgents das Ausweich-Feature nutzen können, muss das Property enable_avoidance
auf true
gesetzt werden.
Das Signal velocity_computed
des Nodes NavigationAgent muss verbunden sein, um das Ergebnis der sicheren Geschwindigkeitsberechnung zu erhalten.
Verwenden Sie set_velocity()
auf dem NavigationAgent-Node in _physics_process()
, um den Agenten mit der aktuellen Geschwindigkeit des Parent-Node zu aktualisieren.
Solange das Ausweich-Feature für den Agenten aktiviert ist, wird der Vektor safe_velocity
zusammen mit dem velocity_computed-Signal in jedem Physik-Frame empfangen. Dieser Geschwindigkeitsvektor sollte verwendet werden, um den Parent-Node des NavigationAgent zu bewegen, um Kollisionen mit anderen ausweichenden Agenten oder Ausweich-Hindernissen zu vermeiden.
Bemerkung
Nur andere Agenten auf der gleichen Map, die selbst zum Ausweichen eingetragen sind, werden bei der Ausweichberechnung berücksichtigt.
Die folgenden Propertys von NavigationAgent sind für zum Ausweichen relevant:
Die Property
Höhe
ist nur in 3D verfügbar. Die Höhe bestimmt zusammen mit der aktuellen globalen y-Achsenposition des Agenten die vertikale Platzierung des Agenten in der Ausweichsimulation. Agenten, die das 2D-Ausweichverfahren verwenden, ignorieren automatisch andere Agenten oder Hindernisse, die sich unter oder über ihnen befinden.Das Property
Radius
steuert die Größe des Ausweichkreises (in 3D-Fall einer Kugel) um den Agenten. Dieser Bereich beschreibt den Body des Agenten und nicht die Distanz des Ausweichmanövers.Die Property
neighbor_distance
steuert den Suchradius des Agenten bei der Suche nach anderen Agenten, denen ausgewichen werden soll. Ein kleinerer Wert verringert die Berechnungskosten.Die Property
max_neighbors
steuert, wie viele andere Agenten bei der Ausweichberechnung berücksichtigt werden, wenn sie alle einen überlappenden Radius haben. Ein niedriger Wert reduziert die Verarbeitungskosten, aber ein zu niedriger Wert kann dazu führen, dass Agenten as Ausweichen ignorieren.Die Propertys
time_horizon_agents
undtime_horizon_obstacles
steuern die Ausweichvorhersagezeit für andere Agenten oder Hindernisse in Sekunden. Wenn Agenten ihre sicheren Geschwindigkeiten berechnen, wählen sie Geschwindigkeiten, die für diese Anzahl von Sekunden gehalten werden können, ohne mit einem anderen Ausweichobjekt zu kollidieren. Die Vorhersagezeit sollte so niedrig wie möglich gehalten werden, da die Agenten ihre Geschwindigkeit verlangsamen werden, um eine Kollision innerhalb dieses Zeitrahmens zu vermeiden.Die Property
max_speed
steuert die maximale Geschwindigkeit, die für die Ausweichberechnung des Agenten erlaubt ist. Wenn sich die Parents des Agenten schneller als dieser Wert bewegen, könnte die Ausweichberechnungsafe_velocity
nicht genau genug sein, um eine Kollision zu vermeiden.Die Property
use_3d_avoidance
schaltet den Agenten bei der nächsten Aktualisierung zwischen der 2D-Ausweichen (xz-Achse) und der 3D-Ausweichen (xyz-Achse) um. Beachten Sie, dass das 2D-Ausweichen und das 3D-Ausweichen in separaten Ausweichsimulationen ablaufen, so dass sich Agenten, die zwischen diesen beiden Methoden wechseln, nicht gegenseitig beeinflussen.Die Propertys
avoidance_layers
undavoidance_mask
sind Bitmasken, ähnlich wie z.B. bei physikalischen Ebenen. Agenten weichen nur anderen Ausweichobjekten aus, die sich auf einem Ausweich-Layer befinden, der mit mindestens einem ihrer eigenen Ausweichmasken-Bits übereinstimmt.
avoidance_priority
bewirkt, dass Agenten mit einer höheren Priorität Agenten mit einer niedrigeren Priorität ignorieren. Dies kann verwendet werden, um bestimmten Agenten in der Ausweichsimulation mehr Bedeutung zu geben, z.B. wichtigen NPC-Charakteren, ohne ständig ihren gesamten Ausweich-Layer oder ihre Maske zu ändern.
Ausweichmanöver existieren in ihrem eigenen Raum und haben keine Informationen von Navigations-Meshes oder physikalischen Kollisionen. Unter der Haube sind Ausweichagenten einfach Kreise mit verschiedenen Radien auf einer flachen 2D-Ebene oder Kugeln in einem ansonsten leeren 3D-Raum. NavigationObstacles können verwendet werden, um einige Umgebungseinschränkungen zur Ausweichsimulation hinzuzufügen, siehe Verwenden von NavigationObstacles.
Bemerkung
Das Ausweichen hat keinen Einfluss auf die Wegfindung. Es sollte als zusätzliche Option für sich ständig bewegende Objekte betrachtet werden, die nicht effizient in ein Navigations-Mesh (um)gebacken werden können, um sich um sie herum zu bewegen.
Die Verwendung der NavigationAgent-Property enable_avoidance
ist die bevorzugte Option zum Ein- und Ausschalten des Ausweichmodus. Die folgenden Codeschnipsel können verwendet werden, um das Ausweichen bei Agenten zu aktivieren, Ausweich-Callbacks zu erstellen oder zu löschen oder den Ausweichmodus zu wechseln.
extends NavigationAgent2D
var agent: RID = get_rid()
# Enable avoidance
NavigationServer2D.agent_set_avoidance_enabled(agent, true)
# Create avoidance callback
NavigationServer2D.agent_set_avoidance_callback(agent, Callable(self, "_avoidance_done"))
# Disable avoidance
NavigationServer2D.agent_set_avoidance_enabled(agent, false)
# Delete avoidance callback
NavigationServer2D.agent_set_avoidance_callback(agent, Callable())
extends NavigationAgent3D
var agent: RID = get_rid()
# Enable avoidance
NavigationServer3D.agent_set_avoidance_enabled(agent, true)
# Create avoidance callback
NavigationServer3D.agent_set_avoidance_callback(agent, Callable(self, "_avoidance_done"))
# Switch to 3D avoidance
NavigationServer3D.agent_set_use_3d_avoidance(agent, true)
# Disable avoidance
NavigationServer3D.agent_set_avoidance_enabled(agent, false)
# Delete avoidance callback
NavigationServer3D.agent_set_avoidance_callback(agent, Callable())
# Switch to 2D avoidance
NavigationServer3D.agent_set_use_3d_avoidance(agent, false)
NavigationAgent-Skriptvorlagen¶
Die folgenden Abschnitte enthalten Skriptvorlagen für Nodes, die häufig mit NavigationAgents verwendet werden.
Akteur als Node3D¶
Dieses Skript fügt grundlegende Navigationsbewegungen zu einem Node3D mit einem NavigationAgent3D-Node hinzu.
extends Node3D
@export var movement_speed: float = 4.0
@onready var navigation_agent: NavigationAgent3D = get_node("NavigationAgent3D")
var movement_delta: float
func _ready() -> void:
navigation_agent.velocity_computed.connect(Callable(_on_velocity_computed))
func set_movement_target(movement_target: Vector3):
navigation_agent.set_target_position(movement_target)
func _physics_process(delta):
if navigation_agent.is_navigation_finished():
return
movement_delta = movement_speed * delta
var next_path_position: Vector3 = navigation_agent.get_next_path_position()
var new_velocity: Vector3 = global_position.direction_to(next_path_position) * movement_delta
if navigation_agent.avoidance_enabled:
navigation_agent.set_velocity(new_velocity)
else:
_on_velocity_computed(new_velocity)
func _on_velocity_computed(safe_velocity: Vector3) -> void:
global_position = global_position.move_toward(global_position + safe_velocity, movement_delta)
Akteur als CharacterBody3D¶
Dieses Skript fügt grundlegende Navigationsbewegungen zu einem CharacterBody3D mit einem NavigationAgent3D-Child-Node hinzu.
extends CharacterBody3D
@export var movement_speed: float = 4.0
@onready var navigation_agent: NavigationAgent3D = get_node("NavigationAgent3D")
func _ready() -> void:
navigation_agent.velocity_computed.connect(Callable(_on_velocity_computed))
func set_movement_target(movement_target: Vector3):
navigation_agent.set_target_position(movement_target)
func _physics_process(delta):
if navigation_agent.is_navigation_finished():
return
var next_path_position: Vector3 = navigation_agent.get_next_path_position()
var new_velocity: Vector3 = global_position.direction_to(next_path_position) * movement_speed
if navigation_agent.avoidance_enabled:
navigation_agent.set_velocity(new_velocity)
else:
_on_velocity_computed(new_velocity)
func _on_velocity_computed(safe_velocity: Vector3):
velocity = safe_velocity
move_and_slide()
Akteur als RigidBody3D¶
Dieses Skript fügt grundlegende Navigationsbewegungen zu einem RigidBody3D mit einem NavigationAgent3D-Child-Node hinzu.
extends RigidBody3D
@export var movement_speed: float = 4.0
@onready var navigation_agent: NavigationAgent3D = get_node("NavigationAgent3D")
func _ready() -> void:
navigation_agent.velocity_computed.connect(Callable(_on_velocity_computed))
func set_movement_target(movement_target: Vector3):
navigation_agent.set_target_position(movement_target)
func _physics_process(delta):
if navigation_agent.is_navigation_finished():
return
var next_path_position: Vector3 = navigation_agent.get_next_path_position()
var new_velocity: Vector3 = global_position.direction_to(next_path_position) * movement_speed
if navigation_agent.avoidance_enabled:
navigation_agent.set_velocity(new_velocity)
else:
_on_velocity_computed(new_velocity)
func _on_velocity_computed(safe_velocity: Vector3):
linear_velocity = safe_velocity