|
@@ -3,8 +3,8 @@
|
|
|
Using NavigationServer
|
|
|
======================
|
|
|
|
|
|
-2D and 3D version of the NavigationServer are available as
|
|
|
-:ref:`NavigationServer2D<class_NavigationServer2D>` and
|
|
|
+2D and 3D version of the NavigationServer are available as
|
|
|
+:ref:`NavigationServer2D<class_NavigationServer2D>` and
|
|
|
:ref:`NavigationServer3D<class_NavigationServer3D>` respectively.
|
|
|
|
|
|
Both 2D and 3D use the same NavigationServer with NavigationServer3D being the primary server. The NavigationServer2D is a frontend that converts 2D positions into 3D positions and back.
|
|
@@ -21,21 +21,21 @@ Every navigation related node in the SceneTree has a function that returns the R
|
|
|
Threading and Synchronisation
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
-The NavigationServer does not update every change immediately but waits until
|
|
|
+The NavigationServer does not update every change immediately but waits until
|
|
|
the end of the ``physics_frame`` to synchronise all the changes together.
|
|
|
|
|
|
-Waiting for synchronisation is required to apply changes to all maps, regions and agents.
|
|
|
-Synchronisation is done because some updates like a recalculation of the entire navigation map are very expensive and require updated data from all other objects.
|
|
|
-Also the NavigationServer uses a ``threadpool`` by default for some functionality like avoidance calculation between agents.
|
|
|
+Waiting for synchronisation is required to apply changes to all maps, regions and agents.
|
|
|
+Synchronisation is done because some updates like a recalculation of the entire navigation map are very expensive and require updated data from all other objects.
|
|
|
+Also the NavigationServer uses a ``threadpool`` by default for some functionality like avoidance calculation between agents.
|
|
|
|
|
|
-Waiting is not required for most ``get()`` functions that only request data from the NavigationServer without making changes.
|
|
|
-Note that not all data will account for changes made in the same frame.
|
|
|
+Waiting is not required for most ``get()`` functions that only request data from the NavigationServer without making changes.
|
|
|
+Note that not all data will account for changes made in the same frame.
|
|
|
E.g. if an avoidance ``agent`` changed the navigation ``map`` this frame the ``agent_get_map()`` function will still return the old map before the synchronisation.
|
|
|
-The exception to this are nodes that store their values internally before sending the update to the NavigationServer.
|
|
|
+The exception to this are nodes that store their values internally before sending the update to the NavigationServer.
|
|
|
When a getter on a node is used for a value that was updated in the same frame it will return the already updated value stored on the node.
|
|
|
|
|
|
The NavigationServer is ``thread-safe`` as it places all API calls that want to make changes in a queue to be executed in the synchronisation phase.
|
|
|
-Synchronisation for the NavigationServer happens in the middle of the physics frame after scene input from scripts and nodes are all done.
|
|
|
+Synchronisation for the NavigationServer happens in the middle of the physics frame after scene input from scripts and nodes are all done.
|
|
|
|
|
|
.. note::
|
|
|
The important takeaway is that most NavigationServer changes take effect after the next physics frame and not immediately.
|
|
@@ -69,22 +69,22 @@ The following functions will be executed in the synchronisation phase only:
|
|
|
2D and 3D NavigationServer differences
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
-NavigationServer2D and NavigationServer3D are equivalent in functionality
|
|
|
+NavigationServer2D and NavigationServer3D are equivalent in functionality
|
|
|
for their dimension and both use the same NavigationServer behind the scene.
|
|
|
|
|
|
-Strictly technical a NavigationServer2D is a myth.
|
|
|
-The NavigationServer2D is a frontend to facilitate conversions of Vector2(x, y) to
|
|
|
-Vector3(x, 0.0, z) and back for the NavigationServer3D API. 2D uses a flat 3D mesh
|
|
|
+Strictly technical a NavigationServer2D is a myth.
|
|
|
+The NavigationServer2D is a frontend to facilitate conversions of Vector2(x, y) to
|
|
|
+Vector3(x, 0.0, z) and back for the NavigationServer3D API. 2D uses a flat 3D mesh
|
|
|
pathfinding and the NavigationServer2D facilitates the conversions.
|
|
|
-When a guide uses just NavigationServer without the 2D or 3D suffix it usually works for both servers
|
|
|
+When a guide uses just NavigationServer without the 2D or 3D suffix it usually works for both servers
|
|
|
by exchange Vector2(x, y) with Vector3(x, 0.0, z) or reverse.
|
|
|
|
|
|
-Technically it is possible to use the tools for creating navigationmesh for the other
|
|
|
-dimension, e..g. baking 2D navigationmesh with the 3D NavigationMesh when using
|
|
|
-flat 3D source geometry or creating 3D flat navigationmesh with the
|
|
|
+Technically it is possible to use the tools for creating navigationmesh for the other
|
|
|
+dimension, e..g. baking 2D navigationmesh with the 3D NavigationMesh when using
|
|
|
+flat 3D source geometry or creating 3D flat navigationmesh with the
|
|
|
polygon outline drawtools of NavigationRegion2D and NavigationPolygons.
|
|
|
|
|
|
-Any RID created with the NavigationServer2D API works on the NavigationServer3D API
|
|
|
+Any RID created with the NavigationServer2D API works on the NavigationServer3D API
|
|
|
as well and both 2D and 3D avoidance agents can exist on the same map.
|
|
|
|
|
|
.. note::
|
|
@@ -115,58 +115,58 @@ Afterwards the function waits for the next physics_frame before continuing with
|
|
|
.. code-tab:: gdscript GDScript
|
|
|
|
|
|
extends Node3D
|
|
|
-
|
|
|
+
|
|
|
func _ready():
|
|
|
# use call deferred to make sure the entire SceneTree Nodes are setup
|
|
|
# else await / yield on 'physics_frame' in a _ready() might get stuck
|
|
|
call_deferred("custom_setup")
|
|
|
|
|
|
func custom_setup():
|
|
|
-
|
|
|
+
|
|
|
# create a new navigation map
|
|
|
- var map : RID = NavigationServer3D.map_create()
|
|
|
+ var map: RID = NavigationServer3D.map_create()
|
|
|
NavigationServer3D.map_set_up(map, Vector3.UP)
|
|
|
NavigationServer3D.map_set_active(map, true)
|
|
|
-
|
|
|
+
|
|
|
# create a new navigation region and add it to the map
|
|
|
- var region : RID = NavigationServer3D.region_create()
|
|
|
+ var region: RID = NavigationServer3D.region_create()
|
|
|
NavigationServer3D.region_set_transform(region, Transform())
|
|
|
NavigationServer3D.region_set_map(region, map)
|
|
|
-
|
|
|
+
|
|
|
# create a procedural navigation mesh for the region
|
|
|
- var new_navigation_mesh : NavigationMesh = NavigationMesh.new()
|
|
|
- var vertices : PackedVector3Array = PoolVector3Array([
|
|
|
+ var new_navigation_mesh: NavigationMesh = NavigationMesh.new()
|
|
|
+ var vertices: PackedVector3Array = PoolVector3Array([
|
|
|
Vector3(0,0,0),
|
|
|
Vector3(9.0,0,0),
|
|
|
Vector3(0,0,9.0)
|
|
|
])
|
|
|
new_navigation_mesh.set_vertices(vertices)
|
|
|
- var polygon : PackedInt32Array = PackedInt32Array([0, 1, 2])
|
|
|
+ var polygon: PackedInt32Array = PackedInt32Array([0, 1, 2])
|
|
|
new_navigation_mesh.add_polygon(polygon)
|
|
|
NavigationServer3D.region_set_navigation_mesh(region, new_navigation_mesh)
|
|
|
-
|
|
|
+
|
|
|
# wait for NavigationServer sync to adapt to made changes
|
|
|
await get_tree().physics_frame
|
|
|
-
|
|
|
+
|
|
|
# query the path from the navigationserver
|
|
|
- var start_position : Vector3 = Vector3(0.1, 0.0, 0.1)
|
|
|
- var target_position : Vector3 = Vector3(1.0, 0.0, 1.0)
|
|
|
- var optimize_path : bool = true
|
|
|
-
|
|
|
- var path : PackedVector3Array = NavigationServer3D.map_get_path(
|
|
|
+ var start_position: Vector3 = Vector3(0.1, 0.0, 0.1)
|
|
|
+ var target_position: Vector3 = Vector3(1.0, 0.0, 1.0)
|
|
|
+ var optimize_path: bool = true
|
|
|
+
|
|
|
+ var path: PackedVector3Array = NavigationServer3D.map_get_path(
|
|
|
map,
|
|
|
start_position,
|
|
|
target_position,
|
|
|
optimize_path
|
|
|
)
|
|
|
-
|
|
|
+
|
|
|
print("Found a path!")
|
|
|
print(path)
|
|
|
|
|
|
Server Avoidance Callbacks
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
-If RVO avoidance agents are registered for avoidance callbacks the NavigationServer dispatches
|
|
|
+If RVO avoidance agents are registered for avoidance callbacks the NavigationServer dispatches
|
|
|
their ``safe_velocity`` signals just before the PhysicsServer synchronisation.
|
|
|
|
|
|
To learn more about NavigationAgents see :ref:`doc_navigation_using_navigationagents`.
|
|
@@ -185,5 +185,5 @@ The simplified order of execution for NavigationAgents that use avoidance:
|
|
|
- PhysicsServer synchronises.
|
|
|
- physics frame ends.
|
|
|
|
|
|
-Therefore moving a physicsbody actor in the callback function with the safe_velocity is perfectly thread- and physics-safe
|
|
|
+Therefore moving a physicsbody actor in the callback function with the safe_velocity is perfectly thread- and physics-safe
|
|
|
as all happens inside the same physics_frame before the PhysicsServer commits to changes and does its own calculations.
|