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.

Utilizzo di NavigationServer

2D and 3D version of the NavigationServer are available as NavigationServer2D and NavigationServer3D respectively.

Communicating with the NavigationServer

To work with the NavigationServer means to prepare parameters for a query that can be sent to the NavigationServer for updates or requesting data.

To reference the internal NavigationServer objects like maps, regions and agents RIDs are used as identification numbers. Every navigation related node in the scene tree has a function that returns the RID for this node.

Threading e sincronizzazione

The NavigationServer does not update every change immediately but waits until the end of the physics frame to synchronize all the changes together.

Waiting for synchronization is required to apply changes to all maps, regions and agents. Synchronization is done because some updates like a recalculation of the entire navigation map are very expensive and require updated data from all other objects. Also the NavigationServer uses a threadpool by default for some functionality like avoidance calculation between agents.

Non è necessasrio attendere per la maggior parte delle funzioni get() che richiedono dati al NavigationServer senza apportare modifiche. Si noti che non tutti i dati terranno conto delle modifiche apportate nello stesso frame. Ad esempio, se un agente di evitamento ha modificato la mappa di navigazione in questo frame, la funzione agent_get_map() restituirà comunque la vecchia mappa prima della sincronizzazione. L'eccezione a questa regola sono i nodi che memorizzano i propri valori internamente prima di inviare l'aggiornamento al NavigationServer. Quando si utilizza un getter su un nodo per un valore che è stato aggiornato nello stesso frame, verrà restituito il valore già aggiornato memorizzato sul nodo.

Il NavigationServer è thread-safe poiché inserisce tutte le chiamate API che desiderano apportare modifiche in una coda per essere eseguite nella fase di sincronizzazione. La sincronizzazione per il NavigationServer avviene a metà del frame di fisca, dopo che tutti gli input della scena provenienti da script e nodi sono stati elaborati.

Nota

La cosa importante da ricordare è che la maggior parte delle modifiche apportate al NavigationServer hanno effetto solo dopo il frame di fisica successivo e non immediatamente. Questo include tutte le modifiche apportate dai nodi relativi alla navigazione nell'albero di scene o tramite script.

Nota

Tutte le funzioni di impostazione (set) e cancellazione (delete) richiedono la sincronizzazione.

Differenza tra il NavigationServer 2D e 3D

NavigationServer2D e NavigationServer3D sono equivalenti in funzionalità per le loro dimensioni.

Tecnicamente è possibile utilizzare gli strumenti per creare mesh di navigazione in una dimensione anche per l'altra dimensione, ad esempio generando una mesh di navigazione 2D con il NavigationMesh 3D quando si utilizza una geometria sorgente 3D piatta, oppure creando mesh di navigazione 3D piatte con gli strumenti per disegnare contorni poligonali di NavigationRegion2D e NavigationPolygon.

Attendere per la sincronizzazione

At the start of the game, a new scene or procedural navigation changes any path query to a NavigationServer will return empty or wrong.

La mappa di navigazione è ancora vuota o non aggiornata a questo punto. Tutti i nodi dell'albero di scene devono prima caricare i propri dati relativi alla navigazione sul NavigationServer. Ogni mappa, regione o agente aggiunto o modificato deve essere registrato con il NavigationServer. Successivamente, il NavigationServer necessita di un frame di fisica per sincronizzare e aggiornare le mappe, regioni e agenti.

One workaround is to make a deferred call to a custom setup function (so all nodes are ready). The setup function makes all the navigation changes, e.g. adding procedural stuff. Afterwards the function waits for the next physics frame before continuing with path queries.

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)

Server Avoidance Callbacks

If RVO avoidance agents are registered for avoidance callbacks the NavigationServer dispatches their velocity_computed signals just before the PhysicsServer synchronization.

To learn more about NavigationAgents see Utilizzo dei NavigationAgent.

The simplified order of execution for NavigationAgents that use avoidance:

  • comincia il frame di fisica.

  • _physics_process(delta).

  • velocity property is set on NavigationAgent Node.

  • Agent sends velocity and position to NavigationServer.

  • NavigationServer waits for synchronization.

  • NavigationServer sincronizza e calcola le velocità di evitamento per tutti gli agenti di evitamento registrati.

  • NavigationServer invia il vettore di velocità sicura con i segnali per ciascun agente di evitamento registrato.

  • Gli agenti ricevono il segnale e muovono il loro genitore, ad esempio con move_and_slide o linear_velocity.

  • Il PhysicsServer si sincronizza.

  • termina il frame di fisica.

Pertanto, spostare un attore physicsbody nella funzione di callback con la velocità sicura è perfettamente sicuro per i thread e per la fisica, poiché tutto avviene all'interno dello stesso frame di fisica, prima che il PhysicsServer confermi le modifiche ed esegua i propri calcoli.