Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
애니메이션 트리
NavigationServer의 2D 및 3D 버전은 각각 NavigationServer2D 및 :ref:`NavigationServer3D<class_NavigationServer3D>`로 제공됩니다.
다른 스크립팅 언어와 소통하기
NavigationServer를 사용한다는 것은 업데이트 또는 데이터 요청을 위해 NavigationServer로 보낼 수 있는 **쿼리**에 대한 매개변수를 준비하는 것을 의미합니다.
지도, 지역 및 에이전트 RID와 같은 내부 NavigationServer 개체를 참조하기 위해 식별 번호로 사용됩니다. 씬 트리의 노드와 관련된 모든 탐색에는 이 노드에 대한 RID를 반환하는 함수가 있습니다.
애니메이션 만들기
NavigationServer는 모든 변경 사항을 즉시 업데이트하지 않지만 모든 변경 사항을 함께 동기화하기 위해 **물리 프레임**이 끝날 때까지 기다립니다.
모든 지도, 지역, 에이전트에 변경 사항을 적용하려면 동기화를 기다려야 합니다. 전체 내비게이션 지도의 재계산과 같은 일부 업데이트에는 비용이 많이 들고 다른 모든 개체의 업데이트된 데이터가 필요하기 때문에 동기화가 수행됩니다. 또한 NavigationServer는 에이전트 간 회피 계산과 같은 일부 기능을 위해 기본적으로 **threadpool**을 사용합니다.
변경하지 않고 NavigationServer에서 데이터만 요청하는 대부분의 get() 함수에는 대기가 필요하지 않습니다. 모든 데이터가 동일한 프레임에서 발생한 변경 사항을 설명하는 것은 아닙니다. 예: 회피 에이전트가 이 프레임 내비게이션 지도를 변경한 경우 agent_get_map() 함수는 여전히 동기화 전에 이전 지도를 반환합니다. 이에 대한 예외는 NavigationServer에 업데이트를 보내기 전에 내부적으로 값을 저장하는 노드입니다. 노드의 getter가 동일한 프레임에서 업데이트된 값에 사용되면 노드에 저장된 이미 업데이트된 값을 반환합니다.
NavigationServer는 변경을 원하는 모든 API 호출을 동기화 단계에서 실행될 큐에 배치하므로 **스레드로부터 안전**합니다. NavigationServer에 대한 동기화는 스크립트 및 노드의 씬 입력이 모두 완료된 후 물리 프레임 중간에 발생합니다.
참고
중요한 점은 대부분의 NavigationServer 변경 사항이 즉시 적용되지 않고 다음 물리 프레임 이후에 적용된다는 것입니다. 여기에는 씬 트리의 탐색 관련 노드 또는 스크립트를 통해 이루어진 모든 변경 사항이 포함됩니다.
참고
모든 setter 및 삭제 기능에는 동기화가 필요합니다.
2D 및 3D NavigationServer 차이점
NavigationServer2D와 NavigationServer3D는 해당 차원의 기능이 동일합니다.
기술적으로 한 차원에서 다른 차원에 대한 내비게이션 메시를 생성하는 도구를 사용하는 것이 가능합니다. 평면 3D 소스 형상을 사용하거나 NavigationRegion2D 및 NavigationPolygons의 다각형 외곽선 그리기 도구를 사용하여 3D 평면 탐색 메쉬를 생성할 때 3D NavigationMesh로 2D 탐색 메쉬를 굽습니다.
문서의 구조
게임 시작 시 새로운 씬 또는 절차적 탐색이 NavigationServer에 대한 경로 쿼리를 변경하면 비어 있거나 잘못된 결과가 반환됩니다.
현재 내비게이션 지도는 여전히 비어 있거나 업데이트되지 않습니다. 씬 트리의 모든 노드는 먼저 탐색 관련 데이터를 NavigationServer에 업로드해야 합니다. 추가되거나 변경된 각 지도, 지역 또는 에이전트는 NavigationServer에 등록되어야 합니다. 이후 NavigationServer에는 지도, 지역 및 에이전트를 업데이트하기 위한 동기화를 위한 **물리 프레임**이 필요합니다.
한 가지 해결 방법은 사용자 정의 설정 기능에 대한 호출을 연기하는 것입니다(따라서 모든 노드가 준비됨). 설정 기능은 모든 탐색 변경을 수행합니다. 절차적인 내용을 추가합니다. 그 후 함수는 경로 쿼리를 계속하기 전에 다음 물리 프레임을 기다립니다.
extends Node3D
func _ready():
# Use call deferred to make sure the entire scene tree nodes are setup
# else await on 'physics_frame' in a _ready() might get stuck.
custom_setup.call_deferred()
func custom_setup():
# Create a new navigation map.
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()
NavigationServer3D.region_set_transform(region, Transform3D())
NavigationServer3D.region_set_map(region, map)
# Create a procedural navigation mesh for the region.
var new_navigation_mesh: NavigationMesh = NavigationMesh.new()
var vertices: PackedVector3Array = PackedVector3Array([
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])
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 navigation server.
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)
using Godot;
public partial class MyNode3D : Node3D
{
public override void _Ready()
{
// Use call deferred to make sure the entire scene tree nodes are setup
// else await on 'physics_frame' in a _Ready() might get stuck.
CallDeferred(MethodName.CustomSetup);
}
private async void CustomSetup()
{
// Create a new navigation map.
Rid map = NavigationServer3D.MapCreate();
NavigationServer3D.MapSetUp(map, Vector3.Up);
NavigationServer3D.MapSetActive(map, true);
// Create a new navigation region and add it to the map.
Rid region = NavigationServer3D.RegionCreate();
NavigationServer3D.RegionSetTransform(region, Transform3D.Identity);
NavigationServer3D.RegionSetMap(region, map);
// Create a procedural navigation mesh for the region.
var newNavigationMesh = new NavigationMesh()
{
Vertices =
[
new Vector3(0.0f, 0.0f, 0.0f),
new Vector3(9.0f, 0.0f, 0.0f),
new Vector3(0.0f, 0.0f, 9.0f),
],
};
int[] polygon = [0, 1, 2];
newNavigationMesh.AddPolygon(polygon);
NavigationServer3D.RegionSetNavigationMesh(region, newNavigationMesh);
// Wait for NavigationServer sync to adapt to made changes.
await ToSignal(GetTree(), SceneTree.SignalName.PhysicsFrame);
// Query the path from the navigation server.
var startPosition = new Vector3(0.1f, 0.0f, 0.1f);
var targetPosition = new Vector3(1.0f, 0.0f, 1.0f);
Vector3[] path = NavigationServer3D.MapGetPath(map, startPosition, targetPosition, optimize: true);
GD.Print("Found a path!");
GD.Print((Variant)path);
}
}
서버 회피 콜백
회피 콜백을 위해 RVO 회피 에이전트가 등록된 경우 NavigationServer는 PhysicsServer 동기화 직전에 해당 velocity_computed 시그널를 디스패치합니다.
GDScript는 GDScript 형식 문자열도 지원합니다.
회피를 사용하는 NavigationAgent의 단순화된 실행 순서는 다음과 같습니다.
물리 프레임 시작.
_physics_process(delta).속도속성은 NavigationAgent 노드에 설정됩니다.에이전트는 NavigationServer에 속도와 위치를 보냅니다.
NavigationServer가 동기화를 기다립니다.
NavigationServer는 등록된 모든 회피 에이전트의 회피 속도를 동기화하고 계산합니다.
NavigationServer는 등록된 각 회피 에이전트에 대해 시그널를 사용하여 안전한 속도 벡터를 보냅니다.
에이전트는 시그널를 수신하고 상위 항목을 이동합니다.
move_and_slide또는 ``linear_velocity``로.PhysicsServer가 동기화됩니다.
물리 프레임이 종료됩니다.
따라서 안전한 속도로 콜백 함수에서 물리 몸체 액터를 움직이는 것은 PhysicsServer가 변경 사항을 적용하고 자체 계산을 수행하기 전에 동일한 물리 프레임 내에서 모든 일이 발생하므로 스레드 및 물리로부터 완벽하게 안전합니다.