Обзор 2D-навигации
Godot предоставляет множество объектов, классов и серверов для упрощения навигации и поиска пути на основе сетки или сетки в 2D- и 3D-играх. В следующем разделе представлен краткий обзор всех доступных объектов навигации в Godot для 2D-сцен и их основных применений.
Godot предоставляет следующие объекты и классы для 2D-навигации:
- Astar2D
Объекты
Astar2Dпредоставляют возможность найти кратчайший путь в графе взвешенных points (точек).Класс AStar2D лучше всего подходит для 2D-игры на основе ячеек, в которой от актеров не требуется достигать какой-либо возможной позиции в области, а только предопределенных, отдельных позиций.
- AstarGrid2D
AstarGrid2D— это вариант AStar2D, специализированный для частичных 2D-сеток.AstarGrid2D проще использовать, когда это применимо, поскольку не требует ручного создания точек и их соединения между собой.
- NavigationServer2D
NavigationServer2Dпредоставляет мощный серверный API для поиска кратчайшего пути между двумя позициями на области, определенной навигационной сеткой.NavigationServer лучше всего подходит для двумерного игрового процесса в реальном времени, требующего от актёров достижения любой возможной позиции в области, заданной навигационной сеткой. Навигация на основе сетки хорошо масштабируется в больших игровых мирах, поскольку большую область часто можно определить одним полигоном, тогда как для этого потребовалось бы множество ячеек сетки.
NavigationServer хранит различные навигационные карты, каждая из которых состоит из регионов с данными навигационной сетки. Агенты могут быть размещены на карте для расчета маршрутов избегания столкновений. Идентификаторы RID используются для ссылки на внутренние карты, регионы и агентов при взаимодействии с сервером.
- Доступны следующие типы RID NavigationServer.
- NavMap RID ((Навигационная карта RID)
Ссылка на конкретную навигационную карту, содержащую регионы и агентов. Карта будет пытаться объединить навигационные сетки регионов по близости. Карта будет синхронизировать регионы и агентов в каждом физическом кадре.
- NavRegion RID (Навигационный регион RID)
Ссылка на конкретную навигационную область, которая может содержать данные навигационной сетки. Область можно включить/отключить или ограничить её использование с помощью битовой маски навигационного слоя.
- NavLink RID (Навигационная ссылка RID)
Ссылка на конкретную навигационную ссылку, которая соединяет две позиции навигационной сетки на произвольных расстояниях.
- NavAgent RID (Навигационный агент RID)
Ссылка на конкретный агент избегания. Избегание определяется значением радиуса.
- NavObstacle RID
Ссылка на конкретное препятствие избегания, используемое для воздействия и ограничения скорости избегания агентов.
Следующие узлы дерева сцены доступны в качестве вспомогательных средств для работы с API NavigationServer2D.
- Узел NavigationRegion2D
Узел, содержащий ресурс NavigationPolygon, который определяет навигационную сетку для NavigationServer2D.
Регион можно включить/отключить.
Использование при поиске пути можно дополнительно ограничить с помощью битовой маски
navigation_layers.NavigationServer2D объединит навигационные сетки регионов по близости для создания объединенной навигационной сетки.
- Узел NavigationLink2D
Узел, соединяющий две позиции на навигационных сетках на произвольных расстояниях для поиска пути.
Ссылку можно включить/отключить.
Связь может быть односторонней или двунаправленной.
Использование при поиске пути можно дополнительно ограничить с помощью битовой маски
navigation_layers.
Ссылки сообщают системе поиска пути о наличии соединения и его стоимости. Фактическое управление агентом и его перемещение должны осуществляться в специальных скриптах.
- Узел NavigationAgent2D
Вспомогательный Узел, используемый для упрощения выполнения общих вызовов API NavigationServer2D для поиска пути и обхода препятствий. Используйте этот Узел с унаследованным родительским Узлом Node2D.
- Узел NavigationObstacle2D
Узел, который можно использовать для управления и ограничения скорости уклонения агентов с включенной функцией уклонения. Этот узел НЕ влияет на поиск пути агентами. Для этого необходимо изменить навигационные сетки.
2D навигационные сетки определяются следующими ресурсами:
- Ресурс NavigationPolygon
Ресурс, содержащий данные двумерной навигационной сетки. Он предоставляет инструменты рисования полигонов, позволяющие определять области навигации как в редакторе, так и во время выполнения.
Узел NavigationRegion2D использует этот ресурс для определения своей области навигации.
NavigationServer2D использует этот ресурс для обновления навигационной сетки отдельных регионов.
Редактор TileSet создает и использует этот ресурс внутренне при определении областей навигации плитки.
См. также
Вы можете увидеть, как работает 2D-навигация в действии, с помощью демонстрационных проектов 2D Navigation Polygon и Grid-based Navigation with AStarGrid2D.
Настройка для 2D-сцены
Следующие шаги демонстрируют базовую настройку минимально жизнеспособной навигации в 2D. Она использует NavigationServer2D и NavigationAgent2D для перемещения по траектории.
Добавление к сцене Узел NavigationRegion2D.
Щелкните узел региона и добавьте новый ресурс NavigationPolygon к узлу региона.
Определите перемещаемую область навигации с помощью инструмента рисования NavigationPolygon. Затем нажмите кнопку Bake NavigationPolygon на панели инструментов.
Примечание
Навигационная сетка определяет область, в которой актёр может стоять и двигаться, используя свой центр. Оставляйте достаточно места между краями навигационного полигона и объектами столкновений, чтобы актёры, следующие по пути, не застревали при столкновениях.
Добавьте в сцену узел CharacterBody2D с базовой формой столкновения и спрайтом или сеткой для визуальных эффектов.
Добавьте узел NavigationAgent2D под узлом символа.
Добавьте следующий скрипт к узлу 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()
using Godot;
public partial class MyCharacterBody2D : CharacterBody2D
{
private NavigationAgent2D _navigationAgent;
private float _movementSpeed = 200.0f;
private Vector2 _movementTargetPosition = new Vector2(70.0f, 226.0f);
public Vector2 MovementTarget
{
get { return _navigationAgent.TargetPosition; }
set { _navigationAgent.TargetPosition = value; }
}
public override void _Ready()
{
base._Ready();
_navigationAgent = GetNode<NavigationAgent2D>("NavigationAgent2D");
// These values need to be adjusted for the actor's speed
// and the navigation layout.
_navigationAgent.PathDesiredDistance = 4.0f;
_navigationAgent.TargetDesiredDistance = 4.0f;
// Make sure to not await during _Ready.
Callable.From(ActorSetup).CallDeferred();
}
public override void _PhysicsProcess(double delta)
{
base._PhysicsProcess(delta);
if (_navigationAgent.IsNavigationFinished())
{
return;
}
Vector2 currentAgentPosition = GlobalTransform.Origin;
Vector2 nextPathPosition = _navigationAgent.GetNextPathPosition();
Velocity = currentAgentPosition.DirectionTo(nextPathPosition) * _movementSpeed;
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;
}
}
Примечание
В первом кадре карта NavigationServer не синхронизировала данные региона, и любой запрос пути вернёт пустой. Дождитесь синхронизации NavigationServer, подождав один кадр в скрипте.