3D 导航概述

Godot 提供了多种对象、类和服务器,可帮助 2D 和 3D 游戏实现基于栅格(Grid)或网格(Mesh)的导航和寻路。下文将对 Godot 中与 3D 场景导航相关的对象及其主要用途进行概述。

Godot 为 3D 导航提供了如下对象和类:

  • Astar3D

    Astar3D 对象能够在由具有权重的构成的图中查找最短路径。

    The AStar3D class is best suited for cell-based 3D gameplay that does not require actors to reach any possible position within an area but only predefined, distinct positions.

  • NavigationServer3D

    NavigationServer3D provides a powerful server API to find the shortest path between two positions on an area defined by a navigation mesh.

    The NavigationServer is best suited for 3D realtime gameplay that does require actors to reach any possible position within a navigation mesh defined area. Mesh-based navigation scales well with large game worlds as a large area can often be defined with a single polygon when it would require many, many grid cells.

    The NavigationServer holds different navigation maps that each consist of regions that hold navigation mesh data. Agents can be placed on a map for avoidance calculation. RIDs are used to reference internal maps, regions, and agents when communicating with the server.

    • NavigationServer 中可用的 RID 类型如下。

      • 导航地图 RID

        Reference to a specific navigation map that holds regions and agents. The map will attempt to join the navigation meshes of the regions by proximity. The map will synchronize regions and agents each physics frame.

      • 导航区块 RID

        Reference to a specific navigation region that can hold navigation mesh data. The region can be enabled / disabled or the use restricted with a navigation layer bitmask.

      • 导航链接 RID

        引用指定的导航链接,能够将两个导航网格上的位置进行连接,无视距离。

      • 导航代理 RID

        Reference to a specific avoidance agent. The avoidance is defined by a radius value.

      • 导航障碍物 RID

        Reference to a specific avoidance obstacle used to affect and constrain the avoidance velocity of agents.

The following scene tree nodes are available as helpers to work with the NavigationServer3D API.

  • NavigationRegion3D 节点

    存放 Navigation Mesh 资源的节点,该资源定义的是 NavigationServer3D 中的导航网格。

    • 区块可以启用/禁用。

    • 通过 navigation_layers 掩码,可以对其在寻路中的使用做进一步的限制。

    • The NavigationServer3D will join the navigation meshes of regions by proximity for a combined navigation mesh.

  • NavigationLink3D 节点

    A Node that connects two positions on navigation meshes over arbitrary distances for pathfinding.

    • 链接可以启用/禁用。

    • 链接可以设为单向或双向。

    • 通过 navigation_layers 掩码,可以对其在寻路中的使用做进一步的限制。

    链接会告诉寻路存在这样的连接、相关的消耗如何。实际的代理处理以及移动需要在自定义脚本中实现。

  • NavigationAgent3D 节点

    A helper Node used to facilitate common NavigationServer3D API calls for pathfinding and avoidance. Use this Node with a Node3D inheriting parent Node.

  • NavigationObstacle3D 节点

    A Node that can be used to affect and constrain the avoidance velocity of avoidance enabled agents. This Node does NOT affect the pathfinding of agents. You need to change the navigation meshes for that instead.

3D 导航网格由以下资源定义:

  • NavigationMesh 资源

    A resource that holds 3D navigation mesh data. It provides 3D geometry baking options to define navigation areas inside the Editor as well as at runtime.

    • NavigationRegion3D 节点使用该资源定义其导航区域。

    • NavigationServer3D 使用该资源更新各个区块的导航网格。

    • The GridMap Editor uses this resource when specific navigation meshes are defined for each grid cell.

参见

可以使用 3D 导航演示项目了解 3D 导航如何运作。

3D 场景的设置

The following steps show a basic setup for minimal viable navigation in 3D. It uses the NavigationServer3D and a NavigationAgent3D for path movement.

  1. 在场景中添加一个 NavigationRegion3D 节点。

  2. 单击该区块节点,向该节点添加一个新的 NavigationMesh 资源。

    ../../_images/nav_3d_min_setup_step1.png

  3. 将一个新的 MeshInstance3D 节点添加为该区块节点的子节点。

  4. 选中该 MeshInstance3D 节点,添加一个新的 PlaneMesh 并将其 XY 大小设为 10。

  5. 再次选中该区块节点,点击顶栏中的“烘焙导航网格”按钮。

    ../../_images/nav_3d_min_setup_step2.png

  6. Now a transparent navigation mesh appears that hovers some distance on top of the PlaneMesh.

    ../../_images/nav_3d_min_setup_step3.png

  7. 在场景中添加一个 CharacterBody3D 节点,设置基础的碰撞形状,添加一些网格方便观察。

  8. 在该角色节点下添加一个 NavigationAgent3D 节点。

    ../../_images/nav_3d_min_setup_step4.webp

  9. 为 CharacterBody3D 节点添加一个脚本,内容如下。场景完全加载后,我们确保设置移动目标,NavigationServer 有时间进行同步。另外,添加一个 Camera3D、一些灯光以及环境,这样才能够看到东西。

GDScriptC#

  1. extends CharacterBody3D
  2. var movement_speed: float = 2.0
  3. var movement_target_position: Vector3 = Vector3(-3.0,0.0,2.0)
  4. @onready var navigation_agent: NavigationAgent3D = $NavigationAgent3D
  5. func _ready():
  6. # These values need to be adjusted for the actor's speed
  7. # and the navigation layout.
  8. navigation_agent.path_desired_distance = 0.5
  9. navigation_agent.target_desired_distance = 0.5
  10. # Make sure to not await during _ready.
  11. call_deferred("actor_setup")
  12. func actor_setup():
  13. # Wait for the first physics frame so the NavigationServer can sync.
  14. await get_tree().physics_frame
  15. # Now that the navigation map is no longer empty, set the movement target.
  16. set_movement_target(movement_target_position)
  17. func set_movement_target(movement_target: Vector3):
  18. navigation_agent.set_target_position(movement_target)
  19. func _physics_process(delta):
  20. if navigation_agent.is_navigation_finished():
  21. return
  22. var current_agent_position: Vector3 = global_position
  23. var next_path_position: Vector3 = navigation_agent.get_next_path_position()
  24. velocity = current_agent_position.direction_to(next_path_position) * movement_speed
  25. move_and_slide()
  1. using Godot;
  2. public partial class MyCharacterBody3D : CharacterBody3D
  3. {
  4. private NavigationAgent3D _navigationAgent;
  5. private float _movementSpeed = 2.0f;
  6. private Vector3 _movementTargetPosition = new Vector3(-3.0f, 0.0f, 2.0f);
  7. public Vector3 MovementTarget
  8. {
  9. get { return _navigationAgent.TargetPosition; }
  10. set { _navigationAgent.TargetPosition = value; }
  11. }
  12. public override void _Ready()
  13. {
  14. base._Ready();
  15. _navigationAgent = GetNode<NavigationAgent3D>("NavigationAgent3D");
  16. // These values need to be adjusted for the actor's speed
  17. // and the navigation layout.
  18. _navigationAgent.PathDesiredDistance = 0.5f;
  19. _navigationAgent.TargetDesiredDistance = 0.5f;
  20. // Make sure to not await during _Ready.
  21. Callable.From(ActorSetup).CallDeferred();
  22. }
  23. public override void _PhysicsProcess(double delta)
  24. {
  25. base._PhysicsProcess(delta);
  26. if (_navigationAgent.IsNavigationFinished())
  27. {
  28. return;
  29. }
  30. Vector3 currentAgentPosition = GlobalTransform.Origin;
  31. Vector3 nextPathPosition = _navigationAgent.GetNextPathPosition();
  32. Velocity = currentAgentPosition.DirectionTo(nextPathPosition) * _movementSpeed;
  33. MoveAndSlide();
  34. }
  35. private async void ActorSetup()
  36. {
  37. // Wait for the first physics frame so the NavigationServer can sync.
  38. await ToSignal(GetTree(), SceneTree.SignalName.PhysicsFrame);
  39. // Now that the navigation map is no longer empty, set the movement target.
  40. MovementTarget = _movementTargetPosition;
  41. }
  42. }

备注

On the first frame the NavigationServer map has not synchronized region data and any path query will return empty. Wait for the NavigationServer synchronization by awaiting one frame in the script.

Previous Next


© 版权所有 2014-present Juan Linietsky, Ariel Manzur and the Godot community (CC BY 3.0). Revision b1c660f7.

Built with Sphinx using a theme provided by Read the Docs.