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.

Usando NavigationPathQueryObjects

Dica

Os parâmetros de consulta de caminho expõem várias opções para melhorar o desempenho da busca de caminhos ou reduzir o consumo de memória.

Eles atendem a necessidades mais avançadas de busca de caminhos que os nós de alto nível nem sempre conseguem cobrir.

Veja as seções de opções respectivas abaixo.

NavigationPathQueryObjects podem ser usados em conjunto com NavigationServer.query_path() para obter um caminho de navegação altamente customizado, incluindo metadados opcionais sobre o caminho.

Isso exige mais configuração em comparação com a obtenção de um NavigationPath normal, mas permite adaptar a busca de caminhos e os dados do caminho fornecidos às diferentes necessidades de um projeto.

NavigationPathQueryObjects consistem em um par de objetos: um objeto NavigationPathQueryParameters que contém as opções de customização para a consulta e um NavigationPathQueryResult que recebe atualizações (regulares) com o caminho resultante e os metadados da consulta.

As versões 2D e 3D de NavigationPathQueryParameters estão disponíveis como NavigationPathQueryParameters2D e NavigationPathQueryParameters3D, respectivamente.

As versões 2D e 3D de NavigationPathQueryResult estão disponíveis como NavigationPathQueryResult2D e NavigationPathQueryResult3D, respectivamente.

Criando uma consulta de caminho básica

Tanto os parâmetros quanto o resultado são usados como um par com a função NavigationServer.query_path().

Para as opções de customização disponíveis, veja mais abaixo. Veja também as descrições de cada parâmetro na referência da classe.

Embora não seja um requisito estrito, a intenção é que ambos os objetos sejam criados uma vez antecipadamente, armazenados em uma variável persistente para o agente e reutilizados para cada consulta de caminho subsequente com parâmetros atualizados.

Reutilizar os mesmos objetos melhora o desempenho ao evitar a criação frequente de objetos ou alocação de memória.

O script a seguir cria os objetos e fornece uma função query_path() para criar novos caminhos de navegação. O caminho resultante é idêntico ao uso de NavigationServer.map_get_path() enquanto reutiliza os objetos.

extends Node2D

# Prepare query objects.
var query_parameters := NavigationPathQueryParameters2D.new()
var query_result := NavigationPathQueryResult2D.new()

func query_path(p_start_position: Vector2, p_target_position: Vector2, p_navigation_layers: int = 1) -> PackedVector2Array:
    if not is_inside_tree():
        return PackedVector2Array()

    var map: RID = get_world_2d().get_navigation_map()

    if NavigationServer2D.map_get_iteration_id(map) == 0:
        # This map has never synced and is empty, no point in querying it.
        return PackedVector2Array()

    query_parameters.map = map
    query_parameters.start_position = p_start_position
    query_parameters.target_position = p_target_position
    query_parameters.navigation_layers = p_navigation_layers

    NavigationServer2D.query_path(query_parameters, query_result)
    var path: PackedVector2Array = query_result.get_path()

    return path

Opções de pós-processamento de caminho

Diferenças de pós-processamento de caminho dependendo do layout do polígono da malha de navegação

Diferenças de pós-processamento de caminho dependendo do layout do polígono da malha de navegação.

Uma busca de consulta de caminho viaja da aresta do polígono da malha de navegação mais próxima até a aresta mais próxima ao longo dos polígonos disponíveis. Se possível, ela constrói um corredor de polígonos em direção ao polígono da posição de destino.

Esse caminho bruto de corredor de polígonos da "busca" não é muito otimizado e geralmente é ruim para os agentes viajarem. Por exemplo, o ponto de aresta mais próximo em um polígono de malha de navegação pode causar um desvio enorme para agentes em polígonos maiores. Para melhorar a qualidade dos caminhos retornados pela consulta, existem várias opções de path_postprocessing.

  • O pós-processamento PATH_POSTPROCESSING_CORRIDORFUNNEL encurta os caminhos afunilando-os ao redor dos cantos dentro do corredor de polígonos disponível.

    Este é o pós-processamento padrão e geralmente também o mais útil, pois fornece o resultado de caminho mais curto dentro do corredor de polígonos disponível. Se o corredor de polígonos já for suboptimal, por exemplo, devido a um layout de malha de navegação suboptimal, o funil pode se alinhar a cantos de polígonos inesperados, causando desvios.

  • O pós-processamento PATH_POSTPROCESSING_EDGECENTERED força todos os pontos do caminho a serem colocados no meio das arestas dos polígonos cruzados dentro do corredor de polígonos disponível.

    Esse pós-processamento geralmente só é útil quando usado com polígonos de malha de navegação estritamente semelhantes a tiles, que são todos de tamanho uniforme e onde o acompanhamento do caminho esperado também é restrito aos centros das células, por exemplo, um jogo de grade típico com movimento restrito aos centros das células da grade.

  • O pós-processamento PATH_POSTPROCESSING_NONE retorna o caminho exatamente como a busca de caminhos viajou dentro do corredor de polígonos disponível.

    Esse pós-processamento é muito útil para depuração (debug), pois mostra como a busca do caminho viajou de ponto de aresta mais próximo a ponto de aresta mais próximo e quais polígonos ela escolheu. Muitos resultados de caminho inesperados ou suboptimais podem ser explicados imediatamente ao olhar para esse caminho bruto e para o corredor de polígonos.

Simplificação de caminho

Dica

A simplificação do caminho pode ajudar agentes com comportamento de direção (steering) ou agentes que tremem em arestas finas de polígonos.

Diferença de pontos de caminho com ou sem simplificação de caminho

Diferença de pontos de caminho com ou sem simplificação de caminho.

Se simplify_path estiver ativado, uma variante do algoritmo de simplificação de caminho Ramer-Douglas-Peucker é aplicada ao caminho. Esse algoritmo endireita os caminhos removendo pontos de caminho menos relevantes, dependendo do simplify_epsilon utilizado.

A simplificação do caminho ajuda com todos os tipos de problemas de movimento de agentes em "campos abertos" que são causados por ter muitas arestas de polígonos desnecessárias. Por exemplo, uma malha de terreno, quando gerada para uma malha de navegação, pode causar uma contagem excessiva de polígonos devido a todas as pequenas variações de altura no terreno (que são quase insignificantes para a busca de caminhos).

A simplificação do caminho também ajuda os agentes com mecânicas de "direção" (steering), porque eles passam a visar apenas os pontos de canto mais críticos do caminho.

Aviso

A simplificação do caminho é um pós-processamento final adicional do caminho. Ela adiciona custos extras de desempenho à consulta, portanto, ative-a apenas quando for realmente necessário.

Nota

A simplificação do caminho é exposta no NavigationServer como uma função genérica. Ela pode ser usada fora das consultas de navegação para todos os tipos de matrizes de posições também.

Metadados de caminho

Dica

Desativar opções de metadados de caminho desnecessárias pode melhorar o desempenho e reduzir o consumo de memória.

Uma consulta de caminho pode retornar metadados adicionais para cada ponto do caminho.

  • A flag PATH_METADATA_INCLUDE_TYPES coleta um array com as informações primitivas sobre os proprietários dos pontos, por exemplo, se um ponto pertence a uma região ou a um link.

  • A flag PATH_METADATA_INCLUDE_RIDS coleta um array com os RIDs os proprietários dos pontos. Dependendo da primitiva do proprietário do ponto, esses RIDs podem ser usados com as várias funções do NavigationServer relacionadas a regiões ou links.

  • A flag PATH_METADATA_INCLUDE_OWNERS coleta um array com os ObjectIDs dos proprietários dos pontos. Esses IDs de objeto podem ser usados com @GlobalScope.instance_from_id() para recuperar o nó por trás daquela instância de objeto, por exemplo, um nó NavigationRegion ou NavigationLink.

Por padrão, todos os metadados do caminho são coletados, pois esses metadados podem ser essenciais para uma jogabilidade de navegação mais avançada.

  • Por exemplo, para saber qual ponto do caminho se mapeia para qual objeto ou nó proprietário dentro da SceneTree.

  • Por exemplo, para saber se um ponto do caminho é o início ou o fim de um link de navegação que requer controle por script.

Para os usos mais básicos de caminhos, os metadados nem sempre são necessários. A coleta de metadados de caminho pode ser desativada seletivamente para obter algum desempenho e reduzir o consumo de memória.

Excluindo ou incluindo regiões

Dica

Os filtros de região podem ajudar muito no desempenho em mapas de navegação grandes que são particionados por regiões.

Os parâmetros de consulta permitem limitar a busca de caminhos a malhas de navegação de regiões específicas.

Se um mapa de navegação grande estiver bem particionado em regiões menores, isso pode ajudar muito no desempenho, pois a consulta pode pular um grande número de polígonos em uma das primeiras verificações na busca do caminho.

  • Por padrão e se deixado vazio, todas as regiões do mapa de navegação consultado são incluídas.

  • Se um RID de região for adicionado ao array excluded_regions, a malha de navegação da região será ignorada na busca do caminho.

  • Se um RID de região foi adicionado ao array included_regions, a malha de navegação da região será considerada na busca do caminho e todas as outras regiões não incluídas serão ignoradas também.

  • Se uma região terminar incluída e excluída ao mesmo tempo, ela será considerada excluída.

Os filtros de região são muito eficazes para o desempenho quando combinados com blocos (chunks) de região de navegação alinhados em uma grade. Dessa forma, o filtro pode ser definido para incluir apenas o bloco da posição inicial e os blocos ao redor, em vez de todo o mapa de navegação.

Mesmo que o destino possa estar fora desses blocos ao redor (você sempre pode adicionar mais "anéis"), a busca de caminhos tentará criar um caminho para o polígono mais próximo do destino. Isso geralmente cria meio-caminhos que seguem na direção geral e que são bons o suficiente, tudo por uma fração do custo de desempenho de uma busca no mapa completo.

A seguinte adição ao script básico de consulta de caminho ilustra a ideia de como integrar um mapeamento de blocos de região com os filtros de região. Este não é um exemplo completo e funcional.

extends Node2D

# ...

var chunk_id_to_region_rid: Dictionary[Vector2i, RID] = {}

func query_path(p_start_position: Vector2, p_target_position: Vector2, p_navigation_layers: int = 1) -> PackedVector2Array:

    # ...

    var regions_around_start_position: Array[RID] = []

    var chunk_rings: int = 1 # Increase for very small regions or more quality.
    var start_chunk_id: Vector2i = floor(p_start_position / float(chunk_size))

    for y: int in range(start_chunk_id.y - chunk_rings, start_chunk_id.y + chunk_rings):
        for x: int in range(start_chunk_id.x - chunk_rings, start_chunk_id.x + chunk_rings):
            var chunk_id: Vector2i = Vector2i(x, y)
            if chunk_id_to_region_rid.has(chunk_id):
                var region: RID = chunk_id_to_region_rid[chunk_id]
                regions_around_start_position.push_back(region)

    query_parameters.included_regions = regions_around_start_position

    # ...

Recorte de caminho e limites

Dica

Limites definidos de forma sensata podem ajudar muito no desempenho em mapas de navegação grandes, especialmente quando os destinos acabam sendo inacessíveis.

Recortando caminhos retornados para distâncias específicas

Recortando caminhos retornados para distâncias específicas.

Os parâmetros de consulta permitem recortar os caminhos retornados para comprimentos específicos. Essas opções recortam o caminho como parte do pós-processamento. O caminho ainda é buscado como se estivesse em seu comprimento total, portanto, terá a mesma qualidade. O recorte do comprimento do caminho pode ser útil para criar caminhos que se adaptem melhor a uma jogabilidade restrita, por exemplo, jogos táticos com alcances de movimento limitados.

  • A propriedade path_return_max_length pode ser usada para recortar o caminho retornado a um comprimento máximo específico.

  • A propriedade path_return_max_radius pode ser usada para recortar o caminho retornado dentro de um raio de círculo (2D) ou esfera (3D) ao redor da posição inicial.

Os parâmetros de consulta permitem limitar a busca do caminho para pesquisar apenas até uma distância específica ou um número específico de polígonos pesquisados. Essas opções são voltadas para o desempenho e afetam diretamente a busca do caminho.

  • A propriedade path_search_max_distance pode ser usada para interromper a busca do caminho ao ultrapassar essa distância a partir da posição inicial.

  • A propriedade path_search_max_polygons pode ser usada para interromper a busca do caminho ao ultrapassar esse número de polígonos pesquisados.

Quando a busca do caminho é interrompida ao atingir um limite, o caminho é resetado e cria um caminho a partir do polígono da posição inicial até o polígono encontrado até o momento que esteja mais próximo da posição de destino.

Aviso

Embora sejam bons para o desempenho, se os valores limite de busca de caminho forem definidos como muito baixos, eles podem afetar a qualidade do caminho de forma muito negativa. Dependendo do layout do polígono e do padrão de busca, os caminhos retornados podem seguir em direções completamente erradas em vez da direção do destino.