Browse Source

Bring 3D navigation example on par with the 2D one

Paul Joannon 2 years ago
parent
commit
7a2aebea60
1 changed files with 50 additions and 10 deletions
  1. 50 10
      tutorials/navigation/navigation_introduction_3d.rst

+ 50 - 10
tutorials/navigation/navigation_introduction_3d.rst

@@ -97,23 +97,42 @@ a NavigationAgent3D for path movement.
 
 
    .. image:: img/nav_3d_min_setup_step4.png
    .. image:: img/nav_3d_min_setup_step4.png
 
 
-#. Add a script to the CharacterBody3D node with the following content. Set a movement target after
-   the scene has fully loaded and the NavigationServer had time to sync. Also, add a Camera3D and some
-   light and environment to see something.
+#. Add a script to the CharacterBody3D node with the following content. We make sure to set a
+   movement target after the scene has fully loaded and the NavigationServer had time to sync.
+   Also, add a Camera3D and some light and environment to see something.
 
 
 .. tabs::
 .. tabs::
  .. code-tab:: gdscript GDScript
  .. code-tab:: gdscript GDScript
 
 
     extends CharacterBody3D
     extends CharacterBody3D
 
 
-    var movement_speed  : float = 4.0
+    var movement_speed : float = 2.0
+    var movement_target_position : Vector3 = Vector2(-3.0,0.0,2.0)
 
 
-    @onready var navigation_agent = $NavigationAgent3D
+    @onready var navigation_agent : NavigationAgent3D = $NavigationAgent3D
+
+    func _ready():
+        # These values need to be adjusted for the actor's speed
+        # and the navigation layout.
+        navigation_agent.path_desired_distance = 0.5
+        navigation_agent.target_desired_distance = 0.5
+
+        # Make sure to not await during _ready.
+        call_deferred("actor_setup")
+
+    func actor_setup():
+        # Wait for the first physics frame so the NavigationServer can sync.
+        await get_tree().physics_frame
+
+        # Now that the navigation map is no longer empty, set the movement target.
+        set_movement_target(movement_target_position)
 
 
     func set_movement_target(movement_target : Vector3):
     func set_movement_target(movement_target : Vector3):
         navigation_agent.set_target_location(movement_target)
         navigation_agent.set_target_location(movement_target)
 
 
     func _physics_process(delta):
     func _physics_process(delta):
+        if navigation_agent.is_target_reached():
+            return
 
 
         var current_agent_position : Vector3 = global_transform.origin
         var current_agent_position : Vector3 = global_transform.origin
         var next_path_position : Vector3 = navigation_agent.get_next_location()
         var next_path_position : Vector3 = navigation_agent.get_next_location()
@@ -131,13 +150,14 @@ a NavigationAgent3D for path movement.
 
 
     public partial class MyCharacterBody3D : CharacterBody3D
     public partial class MyCharacterBody3D : CharacterBody3D
     {
     {
-        private float _movementSpeed = 0.3f;
-
         private NavigationAgent3D _navigationAgent;
         private NavigationAgent3D _navigationAgent;
 
 
+        private float _movementSpeed = 2.0f;
+        private Vector3 _movementTargetPosition = new Vector3(-3.0f, 0.0f, 2.0f);
+
         public Vector3 MovementTarget
         public Vector3 MovementTarget
         {
         {
-            get { _navigationAgent.TargetLocation; }
+            get { return _navigationAgent.TargetLocation; }
             set { _navigationAgent.TargetLocation = value; }
             set { _navigationAgent.TargetLocation = value; }
         }
         }
 
 
@@ -146,12 +166,25 @@ a NavigationAgent3D for path movement.
             base._Ready();
             base._Ready();
 
 
             _navigationAgent = GetNode<NavigationAgent3D>("NavigationAgent3D");
             _navigationAgent = GetNode<NavigationAgent3D>("NavigationAgent3D");
+
+            // These values need to be adjusted for the actor's speed
+            // and the navigation layout.
+            _navigationAgent.PathDesiredDistance = 0.5f;
+            _navigationAgent.TargetDesiredDistance = 0.5f;
+
+            // Make sure to not await during _Ready.
+            Callable.From(ActorSetup).CallDeferred();
         }
         }
 
 
         public override void _PhysicsProcess(double delta)
         public override void _PhysicsProcess(double delta)
         {
         {
             base._PhysicsProcess(delta);
             base._PhysicsProcess(delta);
 
 
+            if (_navigationAgent.IsTargetReached())
+            {
+                return;
+            }
+
             Vector3 currentAgentPosition = GlobalTransform.origin;
             Vector3 currentAgentPosition = GlobalTransform.origin;
             Vector3 nextPathPosition = _navigationAgent.GetNextLocation();
             Vector3 nextPathPosition = _navigationAgent.GetNextLocation();
 
 
@@ -162,11 +195,18 @@ a NavigationAgent3D for path movement.
 
 
             MoveAndSlide();
             MoveAndSlide();
         }
         }
+
+        private async void ActorSetup()
+        {
+            // Wait for the first physics frame so the NavigationServer can sync.
+            await ToSignal(GetTree(), SceneTree.SignalName.PhysicsFrame);
+
+            // Now that the navigation map is no longer empty, set the movement target.
+            MovementTarget = _movementTargetPosition;
+        }
     }
     }
 
 
 .. note::
 .. note::
 
 
     On the first frame the NavigationServer map has not synchronised region data and any path query
     On the first frame the NavigationServer map has not synchronised region data and any path query
     will return empty. Await one frame to pause scripts until the NavigationServer had time to sync.
     will return empty. Await one frame to pause scripts until the NavigationServer had time to sync.
-
-    You can find more details about this in the :ref:`2D Navigation Overview page <doc_navigation_overview_2d>`.