Browse Source

Merge pull request #6045 from smix8/doc_navigation_maps_and_actors_4.x

Add navigation doc for maps, different actor types, and actor locomotion
Max Hilbrunner 2 years ago
parent
commit
4563c48a82

BIN
tutorials/navigation/img/nav_actor_locomotion.png


BIN
tutorials/navigation/img/nav_actor_sizes.png


BIN
tutorials/navigation/img/nav_maps.png


+ 3 - 0
tutorials/navigation/index.rst

@@ -7,3 +7,6 @@ Navigation
 
 
    navigation_introduction_2d.rst
    navigation_introduction_2d.rst
    navigation_introduction_3d.rst
    navigation_introduction_3d.rst
+   navigation_using_navigationmaps
+   navigation_different_actor_types
+   navigation_different_actor_locomotion

+ 43 - 0
tutorials/navigation/navigation_different_actor_locomotion.rst

@@ -0,0 +1,43 @@
+.. _doc_navigation_different_actor_locomotion:
+
+Support different actor locomotion
+==================================
+
+.. image:: img/nav_actor_locomotion.png
+
+To support different actor locomotion like crouching and crawling, a similar 
+map setup as supporting :ref:`doc_navigation_different_actor_types` is required.
+
+Bake different navigation meshes with an appropriate height for crouched 
+or crawling actors so they can find paths through those narrow sections in your game world.
+
+When an actor changes locomotion state, e.g. stands up, starts 
+crouching or crawling, query the appropriate map for a path.
+
+If the avoidance behavior should also change with the locomotion e.g. only avoid while standing or only avoid 
+other agents in the same locomotion state, switch the actors's avoidance agent to another avoidance map with each locomotion change.
+
+.. tabs::
+ .. code-tab:: gdscript GDScript
+    
+    func update_path():
+        
+        if actor_standing:
+            path = NavigationServer3D.map_get_path(standing_navigation_map_rid, start_position, target_position, true)
+        elif actor_crouching:
+            path = NavigationServer3D.map_get_path(crouched_navigation_map_rid, start_position, target_position, true)
+        elif actor_crawling:
+            path = NavigationServer3D.map_get_path(crawling_navigation_map_rid, start_position, target_position, true)
+    
+    func change_agent_avoidance_state():
+        
+        if actor_standing:
+            NavigationServer3D.agent_set_map(avoidance_agent_rid, standing_navigation_map_rid)
+        elif actor_crouching:
+            NavigationServer3D.agent_set_map(avoidance_agent_rid, crouched_navigation_map_rid)
+        elif actor_crawling:
+            NavigationServer3D.agent_set_map(avoidance_agent_rid, crawling_navigation_map_rid)
+
+.. note::
+
+    While a path query can be execute immediately for multiple maps, the avoidance agent map switch will only take effect after the next server synchronization.

+ 66 - 0
tutorials/navigation/navigation_different_actor_types.rst

@@ -0,0 +1,66 @@
+.. _doc_navigation_different_actor_types:
+
+Support different actor types
+=============================
+
+.. image:: img/nav_actor_sizes.png
+
+To support different actor types due to e.g. their sizes each type requires its own 
+navigation map and navigation mesh baked with an appropriated agent radius and height.
+The same approach can be used to distinguish between e.g. landwalking, swimming or flying agents.
+
+.. note::
+
+   Agents are exclusively defined by a radius and height value for baking navmeshes, pathfinding and avoidance. More complex shapes are not supported.
+
+.. tabs::
+ .. code-tab:: gdscript GDScript
+
+    # create navigationmesh resources for each actor size
+    var navmesh_standard_size : NavigationMesh = NavigationMesh.new()
+    var navmesh_small_size : NavigationMesh = NavigationMesh.new()
+    var navmesh_huge_size : NavigationMesh = NavigationMesh.new()
+    
+    # set appropriated agent parameters
+    navmesh_standard_size.agent_radius = 0.5
+    navmesh_standard_size.agent_height = 1.8
+    navmesh_small_size.agent_radius = 0.25
+    navmesh_small_size.agent_height = 0.7
+    navmesh_huge_size.agent_radius = 1.5
+    navmesh_huge_size.agent_height = 2.5
+    
+    # get the root node for the baking to parse geometry
+    var root_node : Node3D = get_node("NavmeshRootNode")
+    
+    # bake the navigation geometry for each agent size
+    NavigationMeshGenerator.bake(navmesh_standard_size, root_node)
+    NavigationMeshGenerator.bake(navmesh_small_size, root_node)
+    NavigationMeshGenerator.bake(navmesh_huge_size, root_node)
+    
+    # create different navigation maps on the NavigationServer
+    var nav_map_standard : RID = NavigationServer3D.map_create()
+    var nav_map_small : RID = NavigationServer3D.map_create()
+    var nav_map_huge : RID = NavigationServer3D.map_create()
+    
+    # create a region for each map
+    var nav_map_standard_region : RID = NavigationServer3D.region_create()
+    var nav_map_small_region : RID = NavigationServer3D.region_create()
+    var nav_map_huge_region : RID = NavigationServer3D.region_create()
+    
+    # set navigationmesh for each region
+    NavigationServer3D.region_set_navmesh(nav_map_standard_region, navmesh_standard_size)
+    NavigationServer3D.region_set_navmesh(nav_map_small_region, navmesh_small_size)
+    NavigationServer3D.region_set_navmesh(nav_map_huge_region, navmesh_huge_size)
+    
+    # add regions to maps
+    nav_map_standard_region.region_set_map(nav_map_standard_region, nav_map_standard)
+    nav_map_small_region.region_set_map(nav_map_small_region, nav_map_small)
+    nav_map_huge_region.region_set_map(nav_map_huge_region, nav_map_huge)
+    
+    # wait a physics frame for sync
+    await get_tree().physics_frame
+    
+    # query paths for each size
+    var path_standard_agent = NavigationServer3D.map_get_path(nav_map_standard, start_pos, end_pos, true)
+    var path_small_agent = NavigationServer3D.map_get_path(navmesh_small_size, start_pos, end_pos, true)
+    var path_huge_agent = NavigationServer3D.map_get_path(nav_map_huge, start_pos, end_pos, true)

+ 77 - 0
tutorials/navigation/navigation_using_navigationmaps.rst

@@ -0,0 +1,77 @@
+.. _doc_navigation_using_navigationmaps:
+
+Using NavigationMaps
+====================
+
+.. image:: img/nav_maps.png
+
+A NavigationMap is an abstract navigation world on the NavigationServer identified by a NavigationServer :ref:`RID<class_RID>`.
+
+A map can hold and connect a near infinite number of navigation regions with navigation meshes to build the traversable areas of a game world for pathfinding.
+
+A map can be joined by avoidance agents to process collision avoidance between the avoidance agents.
+
+.. note::
+
+    Different NavigationMaps are completely isolated from each other but navigation regions 
+    and avoidance agents can switch between different maps once every server synchronization.
+
+Default navigation maps
+~~~~~~~~~~~~~~~~~~~~~~~
+
+By default Godot creates a navigation map RID for each :ref:`World2D<class_World2D>` and :ref:`World3D<class_World3D>` of the root viewport.
+
+The 2D default navigation ``map`` can be obtained with ``get_world_2d().get_navigation_map()`` from any :ref:`Node2D<class_Node2D>` inheriting Node.
+
+The 3D default navigation ``map`` can be obtained with ``get_world_3d().get_navigation_map()`` from any :ref:`Node3D<class_Node3D>` inheriting Node.
+
+.. tabs::
+ .. code-tab:: gdscript GDScript
+
+    extends Node2D
+    
+    var default_2d_navigation_map_rid : RID = get_world_2d().get_navigation_map()
+
+.. tabs::
+ .. code-tab:: gdscript GDScript
+
+    extends Node3D
+    
+    var default_3d_navigation_map_rid : RID = get_world_3d().get_navigation_map()
+
+Creating new navigation maps
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The NavigationServer can create and support as many navigation maps as are required for specific gameplay.
+Additional navigation maps are created and maintained by using the NavigationServer API 
+directly e.g. to support different avoidance agent or actor locomotion types.
+
+For example uses of different navigation maps see :ref:`doc_navigation_different_actor_types` and :ref:`doc_navigation_different_actor_locomotion`.
+
+Each navigation map synchronizes queued changes to its navigation regions and avoidance agents individually. 
+A navigation map that has not received changes will consume little to no processing time. 
+Navigation regions and avoidance agents can only be part of a single navigations map but they can switch maps at any time.
+
+.. note::
+
+    A navigation map switch will take effect only after the next NavigationServer synchronization.
+
+.. tabs::
+ .. code-tab:: gdscript GDScript
+
+    extends Node2D
+    
+    var new_navigation_map : RID = NavigationServer2D.map_create()
+    NavigationServer2D.map_set_active(true)
+
+.. tabs::
+ .. code-tab:: gdscript GDScript
+
+    extends Node3D
+    
+    var new_navigation_map : RID = NavigationServer3D.map_create()
+    NavigationServer3D.map_set_active(true)
+
+.. note::
+
+    There is no difference between navigation maps created with the NavigationServer2D API or the NavigationServer3D API.