Verwenden von Navigations-Meshes
2D- und 3D-Versionen des Navigations-Mesh sind als NavigationPolygon bzw. NavigationMesh verfügbar.
Bemerkung
Ein Navigations-Mesh beschreibt nur einen durchquerbaren Bereich für die zentrale Position eines Agenten. Alle Radiuswerte, die ein Agent haben kann, werden ignoriert. Wenn Sie möchten, dass die Wegfindung die (Kollisions-) Größe eines Agenten berücksichtigt, müssen Sie das Navigations-Mesh entsprechend verkleinern.
Die Navigation funktioniert unabhängig von anderen Teilen der Engine wie Rendering oder Physik. Navigations-Meshes sind die einzigen Dinge, die bei der Wegfindung berücksichtigt werden, d.h. visuelle Elemente und Collision Shapes werden vom Navigationssystem komplett ignoriert. Wenn Sie andere Daten (wie z.B. das Bildmaterial) bei der Wegfindung berücksichtigen wollen, müssen Sie Ihre Navigations-Meshes entsprechend anpassen. Der Prozess der Berücksichtigung von Navigationsbeschränkungen in Navigations-Meshes wird gemeinhin als "Navigations-Mesh-Backen" bezeichnet.
Ein Navigations-Mesh beschreibt eine Fläche, auf der ein Agent sicher stehen kann, wobei sein Zentrum mit den Physik-Shapes verglichen wird, die äußere Kollisionsgrenzen beschreiben.
Wenn Sie beim Verfolgen von Navigationspfaden auf Clipping- oder Kollisionsprobleme stoßen, denken Sie immer daran, dass Sie dem Navigationssystem über ein geeignetes Mesh mitteilen müssen, was Sie vorhaben. Das Navigationssystem selbst wird nie wissen, ob es sich um einen Baum, einen Felsen, eine Wand oder ein visuelles Mesh handelt, denn es weiß nur: "mir wurde gesagt, dass ich diesen Weg sicher gehen kann, weil er auf einem Navigations-Mesh liegt".
Das Backen eines Navigations-Meshes kann entweder durch die Verwendung einer NavigationRegion2D oder NavigationRegion3D, oder durch die direkte Verwendung der NavigationServer2D- und NavigationServer3D-API erreicht werden.
Backen eines Navigations-Meshes mit einer NavigationRegion
Backen eines Navigations-Meshes mit Agentenradiusversatz zur Geometrie.
Das Backen des Navigations-Meshs wird durch den NavigationRegion-Node zugänglicher gemacht. Beim Backen mit einem NavigationRegion-Node werden die einzelnen Schritte des Parsens, Backens und der Regionsaktualisierung in einer Funktion zusammengefasst.
Die Nodes sind in 2D und 3D als NavigationRegion2D bzw. NavigationRegion3D verfügbar.
Tipp
The navigation mesh source_geometry_mode can be switched to parse specific node group names so nodes that should be baked can be placed anywhere in the scene.
Wenn ein NavigationRegion2D-Node im Editor ausgewählt wird, erscheinen in der oberen Leiste des Editors die Backoptionen sowie die Polygonzeichenwerkzeuge.
Damit die Region funktioniert, muss eine NavigationPolygon-Ressource hinzugefügt werden.
Die Propertys zum Analysieren und Backen eines Navigations-Mesh sind dann Teil der verwendeten Ressource und können im Ressourceninspektor gefunden werden.
Das Ergebnis des Parsens der Quellgeometrie kann mit den folgenden Propertys beeinflusst werden.
Der
parsed_geometry_type, der filtert, ob visuelle Objekte oder physikalische Objekte oder beide aus dem SceneTree geparst werden sollen. Für weitere Details darüber, welche Objekte geparst werden und wie, siehe den Abschnitt über das Parsen der Quellgeometrie weiter unten.Die
collision_maskfiltert, welche physischen Kollisionsobjekte einbezogen werden, wenn derparsed_geometry_typestatische Collider enthält.Der
source_geometry_mode, der festlegt, auf welchen Nodes das Parsen beginnen soll und wie der SceneTree durchlaufen werden soll.Der
source_geometry_group_namewird verwendet, wenn nur eine bestimmte Node-Gruppe geparst werden soll. Hängt vom gewähltensource_geometry_modeab.
Nachdem die Quellgeometrie hinzugefügt wurde, kann das Ergebnis des Backens mit den folgenden Propertys gesteuert werden.
Der Parameter
cell_sizelegt die Größe des Rasters fest und sollte mit der Größe der Navigations-Map übereinstimmen.Der
agent_radiusverkleinert das gebackene Mesh, um genügend Spielraum für die Größe des Agenten (Kollisionen) zu haben.
Das Backen der NavigationRegion2D kann auch zur Laufzeit mit Skripten verwendet werden.
var on_thread: bool = true
bake_navigation_polygon(on_thread)
bool onThread = true;
BakeNavigationPolygon(onThread);
Zum schnellen Testen des 2D-Backens mit Default-Einstellungen:
Fügen Sie ein NavigationRegion2D hinzu.
Fügen Sie eine NavigationPolygon-Ressource zur NavigationRegion2D hinzu.
Fügen Sie ein Polygon2D unterhalb der NavigationRegion2D ein.
Zeichnen Sie 1 NavigationPolygon-Kontur mit dem ausgewählten NavigationRegion2D-Zeichenwerkzeug.
Zeichnen Sie 1 Polygon2D-Umriss innerhalb des NavigationPolygon-Umrisses mit dem ausgewählten Polygon2D-Zeichenwerkzeug.
Klicken Sie auf den Editor Back-Button und ein Navigations-Mesh sollte erscheinen.
Wenn ein NavigationRegion3D-Node im Editor ausgewählt wird, werden in der oberen Leiste des Editors Backoptionen angezeigt.
Damit die Region funktioniert, muss eine NavigationMesh-Ressource hinzugefügt werden.
Die Propertys zum Analysieren und Backen eines Navigations-Mesh sind dann Teil der verwendeten Ressource und können im Ressourceninspektor gefunden werden.
Das Ergebnis des Parsens der Quellgeometrie kann mit den folgenden Propertys beeinflusst werden.
Der
parsed_geometry_type, der filtert, ob visuelle Objekte oder physikalische Objekte oder beide aus dem SceneTree geparst werden sollen. Für weitere Details darüber, welche Objekte geparst werden und wie, siehe den Abschnitt über das Parsen der Quellgeometrie weiter unten.Die
collision_maskfiltert, welche physischen Kollisionsobjekte einbezogen werden, wenn derparsed_geometry_typestatische Collider enthält.Der
source_geometry_mode, der festlegt, auf welchen Nodes das Parsen beginnen soll und wie der SceneTree durchlaufen werden soll.Der
source_geometry_group_namewird verwendet, wenn nur eine bestimmte Node-Gruppe geparst werden soll. Hängt vom gewähltensource_geometry_modeab.
Nachdem die Quellgeometrie hinzugefügt wurde, kann das Ergebnis des Backens mit den folgenden Propertys gesteuert werden.
Die
cell_sizeundcell_heightlegen die Größe des Rasterisierungs-Voxel-Rasters fest und sollten der Größe der Navigations-Map entsprechen.Der
agent_radiusverkleinert das gebackene Mesh, um genügend Spielraum für die Größe des Agenten (Kollisionen) zu haben.Die
agent_heightschließt Bereiche aus dem Mesh aus, in die der Agent nicht mehr hineinpasst.Die
agent_max_climbundagent_max_slopeentfernen Bereiche, in denen der Höhenunterschied zwischen benachbarten Voxeln zu groß ist, oder deren Oberfläche zu steil ist.
Warnung
Eine zu kleine cell_size oder cell_height kann so viele Voxel erzeugen, dass das Spiel einfriert oder sogar abstürzt.
Das Backen der NavigationRegion3D kann auch zur Laufzeit mit Skripten verwendet werden.
var on_thread: bool = true
bake_navigation_mesh(on_thread)
bool onThread = true;
BakeNavigationMesh(onThread);
Zum schnellen Testen des 3D-Backens mit Default-Einstellungen:
Fügen Sie ein NavigationRegion3D hinzu.
Fügen Sie eine NavigationMesh-Ressource zur NavigationRegion3D hinzu.
Fügen Sie ein MeshInstance3D unterhalb der NavigationRegion3D hinzu.
Fügen Sie der MeshInstance3D ein PlaneMesh hinzu.
Klicken Sie auf den Editor Back-Button und ein Navigations-Mesh sollte erscheinen.
Backen eines Navigations-Meshes mit dem NavigationServer
Die NavigationServer2D und NavigationServer3D haben API-Funktionen, um jeden Schritt des Navigations-Mesh-Backprozesses einzeln aufzurufen.
Die Funktion
parse_source_geometry_data()kann verwendet werden, um Quellgeometrie in eine wiederverwendbare und serialisierbare Ressource zu zerlegen.Mit
bake_from_source_geometry_data()kann ein Navigations-Mesh aus bereits geparsten Daten gebacken werden, um z.B. Performance-Probleme mit (redundantem) Parsing zur Laufzeit zu vermeiden.Die Funktion
bake_from_source_geometry_data_async()ist die gleiche, aber sie backt das Navigations-Mesh zeitversetzt mit Threads und blockiert nicht den Hauptthread.
Im Vergleich zu einer NavigationRegion bietet der NavigationServer eine feinere Kontrolle über den Backprozess des Navigations-Meshs. Im Gegenzug ist er komplexer in der Anwendung, bietet aber auch mehr erweiterte Optionen.
Einige weitere Vorteile des NavigationServers gegenüber einer NavigationRegion sind:
Der Server kann die Quellgeometrie ohne Backen analysieren, z.B. um sie für eine spätere Verwendung zwischenzuspeichern.
Der Server ermöglicht es, den Root-Node auszuwählen, an dem das Parsen der Quellgeometrie manuell gestartet werden soll.
Der Server kann prozedural erzeugte Quellgeometriedaten akzeptieren und daraus backen.
Der Server kann mehrere Meshes nacheinander backen und dabei dieselben Geometriedaten (wieder)verwenden.
Um Navigationsmeshes mit dem NavigationServer zu backen, ist eine Quellgeometrie erforderlich. Quellgeometrie sind Geometriedaten, die beim Backen von Navigations-Meshes berücksichtigt werden sollten. Sowohl 2D- als auch 3D-Navigations-Meshes werden durch Backen aus der Quellgeometrie erstellt.
2D- und 3D-Versionen der Quellgeometrieressourcen sind als NavigationMeshSourceGeometryData2D bzw. NavigationMeshSourceGeometryData3D verfügbar.
Die Quellgeometrie kann aus visuellen Meshes, aus physikalischen Kollisionen oder aus prozedural erstellten Arrays von Daten wie Umrissen (2D) und Dreiecksflächen (3D) analysiert werden. Der Einfachheit halber wird die Quellgeometrie in der Regel direkt aus Node-Setups im SceneTree geparst. Für das (Neu-)Erstellen von Meshes zur Laufzeit ist zu beachten, dass das Parsen der Geometrie immer auf dem Haupt-Thread stattfindet.
Bemerkung
Der SceneTree ist nicht thread-sicher. Das Parsen der Quellgeometrie aus dem SceneTree kann nur im Haupt-Thread durchgeführt werden.
Warnung
Die Daten von visuellen Meshes und Polygonen müssen von der GPU empfangen werden, was den RenderingServer in diesem Prozess abwürgt. Für das (Neu-)Backen zur Laufzeit sollten bevorzugt Physik-Shapes als geparste Quellgeometrie verwendet werden.
Die Quellgeometrie wird in den Ressourcen gespeichert, so dass die erstellte Geometrie für mehrere Backvorgänge wiederverwendet werden kann. So können z.B. mehrere Navigations-Meshes für unterschiedliche Agentengrößen aus derselben Ausgangsgeometrie erstellt werden. Dies ermöglicht auch das Speichern der Quellgeometrie auf der Festplatte, so dass sie später geladen werden kann, z.B. um den Overhead des erneuten Parsens zur Laufzeit zu vermeiden.
Die Geometriedaten sollten im Allgemeinen sehr einfach gehalten werden. So viele Kanten wie nötig, aber so wenige wie möglich. Besonders in 2D sollte doppelte und verschachtelte Geometrie vermieden werden, da sie die Berechnung von Polygonlöchern erzwingt, was zu gespiegelten Polygonen führen kann. Ein Beispiel für verschachtelte Geometrie wäre ein kleineres StaticBody2D-Shape, das vollständig innerhalb der Grenzen eines anderen StaticBody2D-Shapes platziert wird.
Navigations-Mesh-Blöcke für große Welten backen
Erstellen und Aktualisieren einzelner Navigations-Mesh-Blöcke zur Laufzeit.
Siehe auch
You can see the navigation mesh chunk baking in action in the Navigation Mesh Chunks 2D and Navigation Mesh Chunks 3D demo projects.
Um zu vermeiden, dass die Ränder zwischen verschiedenen Regionsblöcken falsch ausgerichtet sind, verfügen die Navigations-Meshes über zwei wichtige Eigenschaften für den Backprozess des Navigations-Meshes. Die Backgrenze und die Randgröße. Zusammen können sie verwendet werden, um perfekt ausgerichtete Kanten zwischen Regionsblöcken zu gewährleisten.
Navigations-Mesh-Block gebacken mit Backgrenze oder gebacken mit zusätzlicher Randgröße.
Die Backgrenze, bei der es sich um ein achsparalleles Rect2 für 2D und AABB für 3D handelt, schränkt die verwendete Ausgangsgeometrie ein, indem alle Geometrie, die außerhalb der Grenzen liegt, verworfen wird.
Die NavigationPolygon-Propertys baking_rect und baking_rect_offset können verwendet werden, um die 2D-Backgrenze zu erzeugen und zu platzieren.
Die NavigationMesh-Propertys filter_baking_aabb und filter_baking_aabb_offset können verwendet werden, um die 3D-Backgrenze zu erzeugen und zu platzieren.
Wenn nur die Backgrenze gesetzt ist, gibt es immer noch ein weiteres Problem. Das resultierende Navigations-Mesh wird unweigerlich durch notwendige Versätze wie den agent_radius beeinflusst, was dazu führt, dass die Kanten nicht richtig ausgerichtet werden.
Navigations-Mesh-Blöcke mit auffälligen Lücken aufgrund des Radiusversatzes des gebackenen Agenten.
An dieser Stelle kommt die Property border_size für das Navigations-Mesh ins Spiel. Die Randgröße ist ein nach innen gerichteter Abstand der Backgrenze. Die wichtige Eigenschaft der Randgröße ist, dass sie von den meisten Versätzen und Nachbearbeitungen wie dem agent_radius unbeeinflusst ist.
Anstatt die Ausgangsgeometrie zu verwerfen, verwirft die Randgröße Teile der endgültigen Oberfläche des gebackenen Navigations-Meshes. Wenn die Backgrenze groß genug ist, kann die Randgröße die problematischen Oberflächenteile entfernen, so dass nur die beabsichtigte Blockgröße übrig bleibt.
Navigations-Mesh-Blöcke mit ausgerichteten Kanten und ohne Lücken.
Bemerkung
Die Back-Grenzen müssen groß genug sein, um eine angemessene Menge an Quellgeometrie aus allen benachbarten Blöcken einzuschließen.
Warnung
In 3D the functionality of the border size is limited to the xz-axis.
Allgemeine Probleme beim Backen eines Navigations-Meshes
Bei der Erstellung oder dem Backen von Navigations-Meshes gibt es einige typische Benutzerprobleme und wichtige Hinweise zu beachten.
- Das Backen von Navigationsmeshes führt zu Problemen bei der Bildwiederholrate während der Laufzeit
Das Backen des Navigations-Meshes wird standardmäßig in einem Hintergrund-Thread ausgeführt. Solange die Plattform Threads unterstützt, ist das eigentliche Backen nur selten die Ursache für Performance-Probleme (vorausgesetzt, die Geometrie ist ausreichend groß und komplex für Neubacken zur Laufzeit).
Die häufigste Ursache für Performance-Probleme zur Laufzeit ist der Parsing-Schritt für Quellgeometrie, der Nodes und den SceneTree umfasst. Der SceneTree ist nicht thread-sicher, so dass alle Nodes auf dem Hauptthread geparst werden müssen. Einige Nodes mit vielen Daten können sehr schwer und langsam zur Laufzeit zu parsen sein, z.B. hat eine TileMap ein oder mehrere Polygone für jede einzelne Zelle und TileMapLayer zu parsen. Nodes, die Meshes enthalten, müssen die Daten vom RenderingServer anfordern, was den Rendering-Prozess verzögert.
Um die Performance zu verbessern, sollten Sie optimierte Shapes verwenden, z.B. Kollisions-Shape statt detaillierter visueller Meshes, und so viel Geometrie wie möglich im Vorfeld zusammenführen und vereinfachen. Wenn alles nichts hilft, analysieren Sie den SceneTree nicht und fügen Sie die Quellgeometrie prozedural mit Skripten hinzu. Wenn nur reine Datenarrays als Quellgeometrie verwendet werden, kann der gesamte Backprozess in einem Hintergrund-Thread durchgeführt werden.
- Das Navigations-Mesh erzeugt unbeabsichtigte Löcher in 2D.
Das Backen von Navigationsmeshe in 2D erfolgt durch Polygon-Clipping-Operationen auf der Grundlage von Umrisspfaden. Polygone mit "Löchern" sind ein notwendiges Übel, um komplexere 2D-Polygone zu erstellen, können aber für Benutzer mit vielen komplexen Shapes unberechenbar werden.
Um unerwartete Probleme bei der Berechnung von Polygonlöchern zu vermeiden, sollten Sie es vermeiden, Umrisse innerhalb anderer Umrisse desselben Typs (überfahrbar/Hindernis) zu verschachteln. Dies gilt auch für Shapes, die von Nodes geparst wurden. Wenn z.B. ein kleineres StaticBody2D-Shape innerhalb eines größeren StaticBody2D-Shapes platziert wird, kann dies dazu führen, dass das resultierende Polygon gespiegelt wird.
- Das Navigation Mesh erscheint innerhalb der Geometrie in 3D.
Die Backen von Navigations-Meshes in 3D kennt das Konzept des "Innen" nicht. Die zur Rasterung der Geometrie verwendeten Voxelzellen sind entweder belegt oder nicht. Entfernen Sie die Geometrie, die sich auf dem Boden innerhalb der anderen Geometrie befindet. Wenn das nicht möglich ist, fügen Sie eine kleinere "Dummy"-Geometrie mit so wenig Dreiecken wie möglich hinzu, damit die Zellen mit etwas belegt sind.
Eine NavigationObstacle3D-Form, die zum Backen mit dem Navigationsnetz festgelegt ist, kann auch zum Verwerfen der Geometrie verwendet werden.
Mithilfe einer NavigationObstacle3D-Form können unerwünschte Teile des Navigationsnetzes verworfen werden.
Skriptvorlagen für Navigations-Meshes
Das folgende Skript verwendet den NavigationServer, um Quellgeometrie aus dem Szenenbaum zu analysieren, ein Navigations-Mesh zu erstellen und eine Navigationsregion mit dem aktualisierten Navigations-Mesh zu aktualisieren.
extends Node2D
var navigation_mesh: NavigationPolygon
var source_geometry : NavigationMeshSourceGeometryData2D
var callback_parsing : Callable
var callback_baking : Callable
var region_rid: RID
func _ready() -> void:
navigation_mesh = NavigationPolygon.new()
navigation_mesh.agent_radius = 10.0
source_geometry = NavigationMeshSourceGeometryData2D.new()
callback_parsing = on_parsing_done
callback_baking = on_baking_done
region_rid = NavigationServer2D.region_create()
# Enable the region and set it to the default navigation map.
NavigationServer2D.region_set_enabled(region_rid, true)
NavigationServer2D.region_set_map(region_rid, get_world_2d().get_navigation_map())
# Some mega-nodes like TileMap are often not ready on the first frame.
# Also the parsing needs to happen on the main-thread.
# So do a deferred call to avoid common parsing issues.
parse_source_geometry.call_deferred()
func parse_source_geometry() -> void:
source_geometry.clear()
var root_node: Node2D = self
# Parse the obstruction outlines from all child nodes of the root node by default.
NavigationServer2D.parse_source_geometry_data(
navigation_mesh,
source_geometry,
root_node,
callback_parsing
)
func on_parsing_done() -> void:
# If we did not parse a TileMap with navigation mesh cells we may now only
# have obstruction outlines so add at least one traversable outline
# so the obstructions outlines have something to "cut" into.
source_geometry.add_traversable_outline(PackedVector2Array([
Vector2(0.0, 0.0),
Vector2(500.0, 0.0),
Vector2(500.0, 500.0),
Vector2(0.0, 500.0)
]))
# Bake the navigation mesh on a thread with the source geometry data.
NavigationServer2D.bake_from_source_geometry_data_async(
navigation_mesh,
source_geometry,
callback_baking
)
func on_baking_done() -> void:
# Update the region with the updated navigation mesh.
NavigationServer2D.region_set_navigation_polygon(region_rid, navigation_mesh)
using Godot;
public partial class MyNode2D : Node2D
{
private NavigationPolygon _navigationMesh;
private NavigationMeshSourceGeometryData2D _sourceGeometry;
private Callable _callbackParsing;
private Callable _callbackBaking;
private Rid _regionRid;
public override void _Ready()
{
_navigationMesh = new NavigationPolygon();
_navigationMesh.AgentRadius = 10.0f;
_sourceGeometry = new NavigationMeshSourceGeometryData2D();
_callbackParsing = Callable.From(OnParsingDone);
_callbackBaking = Callable.From(OnBakingDone);
_regionRid = NavigationServer2D.RegionCreate();
// Enable the region and set it to the default navigation map.
NavigationServer2D.RegionSetEnabled(_regionRid, true);
NavigationServer2D.RegionSetMap(_regionRid, GetWorld2D().NavigationMap);
// Some mega-nodes like TileMap are often not ready on the first frame.
// Also the parsing needs to happen on the main-thread.
// So do a deferred call to avoid common parsing issues.
CallDeferred(MethodName.ParseSourceGeometry);
}
private void ParseSourceGeometry()
{
_sourceGeometry.Clear();
Node2D rootNode = this;
// Parse the obstruction outlines from all child nodes of the root node by default.
NavigationServer2D.ParseSourceGeometryData(
_navigationMesh,
_sourceGeometry,
rootNode,
_callbackParsing
);
}
private void OnParsingDone()
{
// If we did not parse a TileMap with navigation mesh cells we may now only
// have obstruction outlines so add at least one traversable outline
// so the obstructions outlines have something to "cut" into.
_sourceGeometry.AddTraversableOutline(
[
new Vector2(0.0f, 0.0f),
new Vector2(500.0f, 0.0f),
new Vector2(500.0f, 500.0f),
new Vector2(0.0f, 500.0f),
]);
// Bake the navigation mesh on a thread with the source geometry data.
NavigationServer2D.BakeFromSourceGeometryDataAsync(_navigationMesh, _sourceGeometry, _callbackBaking);
}
private void OnBakingDone()
{
// Update the region with the updated navigation mesh.
NavigationServer2D.RegionSetNavigationPolygon(_regionRid, _navigationMesh);
}
}
extends Node3D
var navigation_mesh: NavigationMesh
var source_geometry : NavigationMeshSourceGeometryData3D
var callback_parsing : Callable
var callback_baking : Callable
var region_rid: RID
func _ready() -> void:
navigation_mesh = NavigationMesh.new()
navigation_mesh.agent_radius = 0.5
source_geometry = NavigationMeshSourceGeometryData3D.new()
callback_parsing = on_parsing_done
callback_baking = on_baking_done
region_rid = NavigationServer3D.region_create()
# Enable the region and set it to the default navigation map.
NavigationServer3D.region_set_enabled(region_rid, true)
NavigationServer3D.region_set_map(region_rid, get_world_3d().get_navigation_map())
# Some mega-nodes like GridMap are often not ready on the first frame.
# Also the parsing needs to happen on the main-thread.
# So do a deferred call to avoid common parsing issues.
parse_source_geometry.call_deferred()
func parse_source_geometry() -> void:
source_geometry.clear()
var root_node: Node3D = self
# Parse the geometry from all mesh child nodes of the root node by default.
NavigationServer3D.parse_source_geometry_data(
navigation_mesh,
source_geometry,
root_node,
callback_parsing
)
func on_parsing_done() -> void:
# Bake the navigation mesh on a thread with the source geometry data.
NavigationServer3D.bake_from_source_geometry_data_async(
navigation_mesh,
source_geometry,
callback_baking
)
func on_baking_done() -> void:
# Update the region with the updated navigation mesh.
NavigationServer3D.region_set_navigation_mesh(region_rid, navigation_mesh)
using Godot;
public partial class MyNode3D : Node3D
{
private NavigationMesh _navigationMesh;
private NavigationMeshSourceGeometryData3D _sourceGeometry;
private Callable _callbackParsing;
private Callable _callbackBaking;
private Rid _regionRid;
public override void _Ready()
{
_navigationMesh = new NavigationMesh();
_navigationMesh.AgentRadius = 0.5f;
_sourceGeometry = new NavigationMeshSourceGeometryData3D();
_callbackParsing = Callable.From(OnParsingDone);
_callbackBaking = Callable.From(OnBakingDone);
_regionRid = NavigationServer3D.RegionCreate();
// Enable the region and set it to the default navigation map.
NavigationServer3D.RegionSetEnabled(_regionRid, true);
NavigationServer3D.RegionSetMap(_regionRid, GetWorld3D().NavigationMap);
// Some mega-nodes like GridMap are often not ready on the first frame.
// Also the parsing needs to happen on the main-thread.
// So do a deferred call to avoid common parsing issues.
CallDeferred(MethodName.ParseSourceGeometry);
}
private void ParseSourceGeometry ()
{
_sourceGeometry.Clear();
Node3D rootNode = this;
// Parse the geometry from all mesh child nodes of the root node by default.
NavigationServer3D.ParseSourceGeometryData(
_navigationMesh,
_sourceGeometry,
rootNode,
_callbackParsing
);
}
private void OnParsingDone()
{
// Bake the navigation mesh on a thread with the source geometry data.
NavigationServer3D.BakeFromSourceGeometryDataAsync(_navigationMesh, _sourceGeometry, _callbackBaking);
}
private void OnBakingDone()
{
// Update the region with the updated navigation mesh.
NavigationServer3D.RegionSetNavigationMesh(_regionRid, _navigationMesh);
}
}
Das folgende Skript verwendet den NavigationServer, um eine Navigationsregion mit prozedural erzeugten Mesh-Daten zu aktualisieren.
extends Node2D
var navigation_mesh: NavigationPolygon
var region_rid: RID
func _ready() -> void:
navigation_mesh = NavigationPolygon.new()
region_rid = NavigationServer2D.region_create()
# Enable the region and set it to the default navigation map.
NavigationServer2D.region_set_enabled(region_rid, true)
NavigationServer2D.region_set_map(region_rid, get_world_2d().get_navigation_map())
# Add vertices for a convex polygon.
navigation_mesh.vertices = PackedVector2Array([
Vector2(0.0, 0.0),
Vector2(100.0, 0.0),
Vector2(100.0, 100.0),
Vector2(0.0, 100.0),
])
# Add indices for the polygon.
navigation_mesh.add_polygon(
PackedInt32Array([0, 1, 2, 3])
)
NavigationServer2D.region_set_navigation_polygon(region_rid, navigation_mesh)
using Godot;
public partial class MyNode2D : Node2D
{
private NavigationPolygon _navigationMesh;
private Rid _regionRid;
public override void _Ready()
{
_navigationMesh = new NavigationPolygon();
_regionRid = NavigationServer2D.RegionCreate();
// Enable the region and set it to the default navigation map.
NavigationServer2D.RegionSetEnabled(_regionRid, true);
NavigationServer2D.RegionSetMap(_regionRid, GetWorld2D().NavigationMap);
// Add vertices for a convex polygon.
_navigationMesh.Vertices =
[
new Vector2(0, 0),
new Vector2(100.0f, 0),
new Vector2(100.0f, 100.0f),
new Vector2(0, 100.0f),
];
// Add indices for the polygon.
_navigationMesh.AddPolygon([0, 1, 2, 3]);
NavigationServer2D.RegionSetNavigationPolygon(_regionRid, _navigationMesh);
}
}
extends Node3D
var navigation_mesh: NavigationMesh
var region_rid: RID
func _ready() -> void:
navigation_mesh = NavigationMesh.new()
region_rid = NavigationServer3D.region_create()
# Enable the region and set it to the default navigation map.
NavigationServer3D.region_set_enabled(region_rid, true)
NavigationServer3D.region_set_map(region_rid, get_world_3d().get_navigation_map())
# Add vertices for a convex polygon.
navigation_mesh.vertices = PackedVector3Array([
Vector3(-1.0, 0.0, 1.0),
Vector3(1.0, 0.0, 1.0),
Vector3(1.0, 0.0, -1.0),
Vector3(-1.0, 0.0, -1.0),
])
# Add indices for the polygon.
navigation_mesh.add_polygon(
PackedInt32Array([0, 1, 2, 3])
)
NavigationServer3D.region_set_navigation_mesh(region_rid, navigation_mesh)
using Godot;
public partial class MyNode3D : Node3D
{
private NavigationMesh _navigationMesh;
private Rid _regionRid;
public override void _Ready()
{
_navigationMesh = new NavigationMesh();
_regionRid = NavigationServer3D.RegionCreate();
// Enable the region and set it to the default navigation map.
NavigationServer3D.RegionSetEnabled(_regionRid, true);
NavigationServer3D.RegionSetMap(_regionRid, GetWorld3D().NavigationMap);
// Add vertices for a convex polygon.
_navigationMesh.Vertices =
[
new Vector3(-1.0f, 0.0f, 1.0f),
new Vector3(1.0f, 0.0f, 1.0f),
new Vector3(1.0f, 0.0f, -1.0f),
new Vector3(-1.0f, 0.0f, -1.0f),
];
// Add indices for the polygon.
_navigationMesh.AddPolygon([0, 1, 2, 3]);
NavigationServer3D.RegionSetNavigationMesh(_regionRid, _navigationMesh);
}
}