2D 導覽總覽

Godot 提供多種物件、類別與伺服器,協助 2D 與 3D 遊戲實作基於格狀或網格的導覽與尋路。以下將快速總覽 Godot 中所有 2D 場景可用的導覽相關物件及其主要用途。

Godot 提供以下物件與類別以支援 2D 導覽:

  • Astar2D

    Astar2D 物件可在具有權重的**點**構成的圖中尋找最短路徑。

    AStar2D 類別最適合用於格狀(儲存格)為基礎的 2D 遊戲,不需角色到達區域中任意位置,而僅需到達預先定義的特定位置。

  • AstarGrid2D

    AstarGrid2D 是 AStar2D 的變體,專為部分 2D 格狀結構(Grid)設計。

    AstarGrid2D 在適用時更容易使用,因為不用手動建立點並將它們連接起來。

  • NavigationServer2D

    NavigationServer2D 提供強大的伺服器 API,可在由導覽網格定義的區域中尋找兩個位置間的最短路徑。

    NavigationServer 最適合用於需讓角色移動至導覽網格區域內任意位置的 2D 即時遊戲。網格(Mesh)導覽適用於大型遊戲世界,因為一大片區域常可僅用單一多邊形定義,若用格子則需許多儲存格。

    NavigationServer 會管理多個導覽地圖,每張地圖由數個包含導覽網格資料的區域組成。代理可被放置於地圖上進行避障計算。與伺服器溝通時,會以 RID 來引用內部地圖、區域與代理。

    可用的 NavigationServer RID 型別如下。
    • 導覽地圖 RID

      引用特定的導覽地圖,地圖中包含區域與代理。地圖會根據區域間距離自動合併導覽網格,並於每個物理影格同步區域與代理。

    • 導覽區域 RID

      引用特定導覽區域,該區域可存放導覽網格資料。可啟用或停用區域,並可用導覽層(navigation layer)位元遮罩限制其用途。

    • 導覽連結 RID

      引用特定導覽連結,可連接導覽網格上兩個任意距離的位置。

    • 導覽代理 RID

      引用特定避障代理。避障效果可透過半徑值設定。

    • 導覽障礙 RID

      引用特定避障障礙,可用來影響及限制代理的避障速度。

以下場景樹節點可作為輔助元件,協助操作 NavigationServer2D API。

  • NavigationRegion2D 節點

    此節點持有 NavigationPolygon 資源,定義供 NavigationServer2D 使用的導覽網格。

    • 區域可設為啟用或停用。

    • 可透過 navigation_layers 位元遮罩進一步限制其在尋路時的用途。

    • NavigationServer2D 會根據區塊間的距離,自動將不同區塊的導覽網格合併為一個整體導覽網格。

  • NavigationLink2D 節點

    此節點可連接導覽網格上兩個任意距離的位置,供尋路使用。

    • 連結可設為啟用或停用。

    • 連結可設為單向或雙向。

    • 可透過 navigation_layers 位元遮罩進一步限制其在尋路時的用途。

    連結會告知尋路系統有此連接,並指定其消耗。實際的代理控制與移動需於自訂腳本處理。

  • NavigationAgent2D 節點

    此輔助節點可簡化常用的 NavigationServer2D 尋路與避障 API 呼叫。請將本節點作為 Node2D 派生節點的子節點使用。

  • NavigationObstacle2D 節點

    此節點可用來影響及限制啟用避障功能的代理的避障速度。注意:此節點**不會**影響代理的尋路,若要改變尋路必須修改導覽網格。

2D 導覽網格由下列資源定義:

  • NavigationPolygon 資源

    存放 2D 導覽網格資料的資源。提供多邊形繪製工具,可於編輯器內或執行時定義導覽區域。

    • NavigationRegion2D 節點會使用該資源來定義其導覽區域。

    • NavigationServer2D 會用此資源更新各區塊的導覽網格。

    • TileSet 編輯器在定義圖塊導覽區域時,會內部建立並使用此資源。

也參考

你可以透過 2D Navigation Polygon使用 AStarGrid2D 的格狀導覽 等範例專案,實際了解 2D 導覽的運作方式。

2D 場景設定

以下步驟說明如何建立最基本可用的 2D 導覽設定,會用到 NavigationServer2D 與 NavigationAgent2D 來進行路徑移動。

  1. 在場景中新增一個 NavigationRegion2D 節點。

  2. 點選該區塊節點,並新增一個 NavigationPolygon 資源至該節點。

    ../../_images/nav_2d_min_setup_step1.png
  3. 使用 NavigationPolygon 繪圖工具定義可移動的導覽區域,然後在工具列點選「Bake NavigationPolygon」按鈕。

    ../../_images/nav_2d_min_setup_step2.png

    備註

    導覽網格定義角色(中心點)可以站立與移動的區域。請於導覽多邊形邊緣與碰撞物件間預留足夠距離,避免路徑跟隨角色被碰撞體卡住。

  4. 在場景新增 CharacterBody2D 節點,設置基本碰撞形狀與 Sprite 或 Mesh 作為顯示用。

  5. 在角色節點下新增一個 NavigationAgent2D 子節點。

    ../../_images/nav_2d_min_setup_step3.webp
  6. 將下列腳本加入 CharacterBody2D 節點。我們會確保於場景完全載入、NavigationServer 完成同步後再設定移動目標。

extends CharacterBody2D

var movement_speed: float = 200.0
var movement_target_position: Vector2 = Vector2(60.0,180.0)

@onready var navigation_agent: NavigationAgent2D = $NavigationAgent2D

func _ready():
    # These values need to be adjusted for the actor's speed
    # and the navigation layout.
    navigation_agent.path_desired_distance = 4.0
    navigation_agent.target_desired_distance = 4.0

    # Make sure to not await during _ready.
    actor_setup.call_deferred()

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: Vector2):
    navigation_agent.target_position = movement_target

func _physics_process(delta):
    if navigation_agent.is_navigation_finished():
        return

    var current_agent_position: Vector2 = global_position
    var next_path_position: Vector2 = navigation_agent.get_next_path_position()

    velocity = current_agent_position.direction_to(next_path_position) * movement_speed
    move_and_slide()

備註

在第一幀時,NavigationServer 的地圖尚未同步區域資料,此時任何路徑查詢都會回傳空結果。請於腳本中等待一幀,讓 NavigationServer 完成同步。