Comprendere i comportamenti dello sterzo seguire il percorso

Il seguente percorso è un problema frequente nello sviluppo del gioco. Questo tutorial copre il percorso successivo comportamento dello sterzo, che consente ai personaggi di seguire un percorso predefinito fatto di punti e linee.

Nota: Sebbene questo tutorial sia scritto usando AS3 e Flash, dovresti essere in grado di utilizzare le stesse tecniche e concetti in quasi tutti gli ambienti di sviluppo di giochi. Devi avere una conoscenza di base dei vettori di matematica.


introduzione

Un percorso che segue il comportamento può essere implementato in diversi modi. L'implementazione originale di Reynolds utilizza un percorso fatto di linee, dove i personaggi li seguono rigorosamente, quasi come un treno su rotaie.

A seconda della situazione, tale precisione potrebbe non essere richiesta. Un personaggio può spostarsi lungo un percorso seguendo le linee, ma usandole come a riferimento, piuttosto che come binari.

L'implementazione del percorso che segue il comportamento in questo tutorial è una semplificazione di quella originale proposta da Reynolds. Produce ancora buoni risultati, ma non si basa su calcoli matematici pesanti come le proiezioni vettoriali.


Definire un percorso

Un percorso può essere definito come un insieme di punti (nodi) collegati da linee. Anche se le curve possono essere utilizzate anche per descrivere un percorso, i punti e le linee sono più facili da gestire e producono quasi gli stessi risultati.

Se è necessario utilizzare le curve, è possibile ridurle a un insieme di punti collegati:


Curve e linee.

La classe Sentiero sarà usato per descrivere il percorso. Fondamentalmente, la classe ha un vettore di punti e alcuni metodi per gestire quell'elenco:

 Percorso di classe pubblica nodi var privati: Vector.; funzione pubblica Path () this.nodes = new Vector.();  public function addNode (node: Vector3D): void nodes.push (node);  funzione pubblica getNodes (): Vector. ritorno nodi; 

Ogni punto del percorso è a Vector3D rappresenta una posizione nello spazio, allo stesso modo del personaggio posizione lavori di proprietà.


Passaggio da nodo a nodo

Per navigare pensato il percorso, il personaggio si sposterà da nodo a nodo fino a raggiungere la fine del percorso.

Ogni punto nel percorso può essere visto come un bersaglio, quindi il comportamento di ricerca può essere utilizzato:

Cerca un punto dopo l'altro.

Il personaggio cercherà il punto corrente fino a quando non viene raggiunto, quindi il punto successivo nel percorso diventa quello corrente e così via. Come descritto in precedenza nel tutorial di evitare le collisioni, le forze di ogni comportamento vengono ricalcolate ad ogni aggiornamento di gioco, quindi la transizione da un nodo a un altro è continua e fluida.

La classe del personaggio avrà bisogno di due ulteriori proprietà per strumentare il processo di navigazione: il nodo corrente (quello che il personaggio sta cercando) e un riferimento al percorso seguito. La classe sarà simile alla seguente:

 public class Boid percorso var pubblico: Path; public var currentNode: int; (...) private function pathFollowing (): Vector3D var target: Vector3D = null; if (percorso! = null) var nodes: Vector. = path.getNodes (); target = nodi [currentNode]; se (distanza (posizione, obiettivo) <= 10)  currentNode += 1; if (currentNode >= nodes.length) currentNode = nodes.length - 1;  restituisce null;  distanza funzione privata (a: Object, b: Object): Number return Math.sqrt ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));  (...)

Il pathFollowing () il metodo è il responsabile della generazione del percorso che segue la forza. Attualmente non produce alcuna forza, ma seleziona correttamente i bersagli.

Il percorso! = null test verifica se il personaggio sta seguendo qualsiasi percorso. Se questo è il caso il nodoCorrente la proprietà viene utilizzata per cercare il target corrente (quello che il personaggio deve cercare) nell'elenco dei punti.

Se la distanza tra il bersaglio corrente e la posizione del personaggio è inferiore a 10, significa che il personaggio ha raggiunto il nodo corrente. Se ciò accade, nodoCorrente viene incrementato di uno, il che significa che il personaggio cercherà il prossimo punto nel percorso. Il processo viene ripetuto fino a quando il percorso non ha più punti.


Calcolo e aggiunta di forze

La forza utilizzata per spingere il personaggio verso ciascun nodo nel percorso è la forza di ricerca. Il pathFollowing () il metodo sceglie già il nodo appropriato, quindi ora deve restituire una forza che spingerà il personaggio verso quel nodo:

 private function pathFollowing (): Vector3D var target: Vector3D = null; if (percorso! = null) var nodes: Vector. = path.getNodes (); target = nodi [currentNode]; se (distanza (posizione, obiettivo) <= 10)  currentNode += 1; if (currentNode >= nodes.length) currentNode = nodes.length - 1;  return target! = null? cercare (obiettivo): nuovo Vector3D (); 

Dopo che il percorso che segue la forza viene calcolato, deve essere aggiunto al vettore di velocità del personaggio come al solito:

 steering = nothing (); // il vettore nullo, che significa "forza zero magnitudo", sterzo = sterzo + percorsoSeguente (); sterzo = troncato (sterzo, max_force) sterzata = sterzo / velocità di massa = troncata (velocità + sterzata, max_velocità) posizione = posizione + velocità

Il percorso che segue la forza di sterzata è estremamente simile al comportamento di inseguimento, in cui il personaggio regola costantemente la propria direzione per catturare l'obiettivo. La differenza sta nel modo in cui il personaggio cerca un bersaglio immobile, che viene ignorato a favore di un altro non appena il personaggio si avvicina troppo.

Il risultato è il seguente:

Percorso che segue in azione. Clicca per mostrare le forze.

Smoothing the Movement

L'attuale implementazione richiede che tutti i personaggi "tocchino" il punto corrente nel percorso per selezionare il prossimo obiettivo. Di conseguenza, un personaggio può eseguire schemi di movimento indesiderati, come muoversi in circolo attorno a un punto finché non viene raggiunto.

In natura, ogni movimento tende ad obbedire al principio del minimo sforzo. Ad esempio, una persona non camminerà per tutto il tempo nel mezzo di un corridoio; se c'è una svolta, la persona camminerà strettamente verso le mura mentre si gira per accorciare la distanza.

Quel modello può essere ricreato aggiungendo un raggio al percorso. Il raggio viene applicato ai punti e può essere visto come il percorso "larghezza". Controllerà quanto lontano un personaggio può muoversi dai punti lungo il percorso:

Influenza del raggio sul percorso successivo.

Se la distanza tra il carattere e il punto è inferiore o uguale al raggio, il punto viene considerato raggiunto. Di conseguenza, tutti i personaggi si sposteranno usando le linee e i punti come guide:

Percorso che segue con raggio. Fai clic sul pulsante "Forza" per mostrare le forze. Fai clic sui pulsanti "+" e "-" per regolare dinamicamente la dimensione del raggio.

Maggiore è il raggio, più ampia è la rotta e maggiore è la distanza che i personaggi manterranno dai punti in curva. Il valore del raggio può essere ottimizzato per produrre diversi modelli seguenti.


Andando avanti e indietro

A volte è utile che un personaggio continui a muoversi dopo aver raggiunto la fine del percorso. In un modello di pattuglia, ad esempio, il personaggio dovrebbe tornare all'inizio del percorso dopo aver raggiunto la fine, seguendo gli stessi punti.

Questo può essere ottenuto aggiungendo il pathDir proprietà alla classe del personaggio; questo è un numero intero che controlla la direzione in cui il personaggio si muove lungo il percorso. Se pathDir è 1, significa che il personaggio si sta muovendo verso la fine del percorso; -1 denota un movimento verso l'inizio.

Il pathFollowing () il metodo può essere cambiato in:

 private function pathFollowing (): Vector3D var target: Vector3D = null; if (percorso! = null) var nodes: Vector. = path.getNodes (); target = nodi [currentNode]; se (distanza (posizione, obiettivo) <= path.radius)  currentNode += pathDir; if (currentNode >= nodes.length || nodoCorrente < 0)  pathDir *= -1; currentNode += pathDir;    return target != null ? seek(target) : new Vector3D(); 

A differenza della versione precedente, il valore di pathDir è ora aggiunto alla proprietà nodoCorrente (invece di aggiungere semplicemente 1). Ciò consente al personaggio di selezionare il punto successivo nel percorso in base alla direzione corrente.

Successivamente, un test controlla se il personaggio ha raggiunto la fine del percorso. Se è il caso, pathDir è moltiplicato per -1, che inverte il suo valore, facendo in modo che il personaggio inverta anche la direzione del movimento.

Il risultato è uno schema di movimento avanti e indietro:

Percorso seguendo con il raggio e il modello avanti e indietro. Fai clic sul pulsante "Forza" per mostrare le forze. Fai clic sui pulsanti "+" e "-" per regolare dinamicamente la dimensione del raggio.

Conclusione

Il comportamento di seguire il percorso consente a qualsiasi personaggio di spostarsi lungo un percorso predefinito. Il percorso è guidato da punti e può essere regolato in modo da essere più ampio o più stretto, producendo schemi di movimento più naturali.

L'implementazione trattata in questo tutorial è una semplificazione del percorso originale che segue il comportamento proposto da Reynolds, ma produce comunque risultati convincenti e accattivanti.