Aggiunta di svolte realistiche
Il prossimo passo è aggiungere curve curve realistiche per le nostre unità, in modo che non sembrino cambiare bruscamente direzione ogni volta che devono girare. Una soluzione semplice prevede l'uso di una spline per smussare gli angoli bruschi in curve. Mentre questo risolve alcune delle preoccupazioni estetiche, si traduce ancora in un movimento fisicamente molto irrealistico per la maggior parte delle unità. Ad esempio, potrebbe cambiare una curva improvvisa di un carro armato in una curva stretta, ma la curva curva sarebbe ancora molto più stretta di quanto il carro armato potrebbe effettivamente eseguire.
Per una soluzione migliore, la prima cosa che dobbiamo sapere è il raggio di sterzata per la nostra unità. Il raggio di sterzata è un concetto abbastanza semplice: se sei in un grande parcheggio nella tua auto, e gira la ruota a sinistra fino in fondo e procedi a guidare in un cerchio, il raggio di quel cerchio è la tua svolta raggio. Il raggio di sterzata di un Maggiolino Volkswagen sarà sostanzialmente più piccolo di quello di un SUV di grandi dimensioni, e il raggio di sterzata di una persona sarà sostanzialmente inferiore a quello di un grande orso che si muove lentamente.
Diciamo che sei ad un certo punto (origine) e puntato in una certa direzione, e devi arrivare ad un altro punto (destinazione), come illustrato nella Figura 5. Il percorso più breve si trova girando a sinistra fino a te puoi, andando in un cerchio fino a quando non sei puntato direttamente verso la destinazione, e quindi procedendo in avanti, oppure girando a destra e facendo la stessa cosa.
Nella Figura 5 il percorso più breve è chiaramente la linea verde in basso. Questo percorso risulta essere abbastanza semplice da calcolare a causa di alcune relazioni geometriche, illustrate nella Figura 6.
In primo luogo calcoliamo la posizione del punto P, che è il centro del nostro cerchio di svolta, ed è sempre il raggio r lontano dal punto iniziale. Se stiamo girando a destra dalla nostra direzione iniziale, significa che P è ad un angolo di (initial_direction - 90) dall'origine, quindi:
angleToP = initial_direction - 90
P.x = Origin.x + r * cos(angleToP)
P.y = Origin.y + r * sin(angleToP)
Ora che conosciamo la posizione del punto centrale P, possiamo calcolare la distanza da P alla destinazione, mostrata come h sul diagramma:
dx = Destination.x - P.x
dy = Destination.y - P.y
h = sqrt(dx*dx + dy*dy)
A questo punto vogliamo anche verificare che la destinazione non sia all'interno del cerchio, perché se fosse, non potremmo mai raggiungerla:
if (h < r)
return false
Ora possiamo calcolare la lunghezza del segmento d, poiché conosciamo già le lunghezze degli altri due lati del triangolo rettangolo, ovvero h e r. Possiamo anche determinare l'angolo dalla relazione del triangolo rettangolo:
d = sqrt(h*h - r*r)
theta = arccos(r / h)
Infine, per capire il punto Q in corrispondenza del quale lasciare il cerchio e iniziare sulla retta, abbiamo bisogno di conoscere l'angolo totale +, ed è facilmente determinato come l'angolo da P alla destinazione:
phi = arctan(dy / dx) [offset to the correct quadrant]
Q.x = P.x + r * cos(phi + theta)
Q.y = P.y + r * sin(phi + theta)
I calcoli sopra riportati rappresentano il percorso con svolta a destra. Il percorso a sinistra può essere calcolato esattamente allo stesso modo, tranne per il fatto che aggiungiamo 90 a initial_direction per il calcolo di angleToP, e successivamente usiamo - invece di +. Dopo aver calcolato entrambi, vediamo semplicemente quale percorso è più breve e usiamo quello.
Nella nostra implementazione di questo algoritmo e di quelli che seguono, utilizziamo una struttura di dati che memorizza fino a quattro distinti "segmenti di linea", ognuno dei quali è dritto o curvo. Per i percorsi curvi qui descritti, vengono utilizzati solo due segmenti: un arco seguito da una linea retta. La struttura dei dati contiene membri che specificano se il segmento è un arco o una linea retta, la lunghezza del segmento e la sua posizione iniziale. Se il segmento è una linea retta, la struttura dei dati specifica anche l'angolo; per gli archi, specifica il centro del cerchio, l'angolo iniziale sul cerchio e i radianti totali coperti dall'arco.
Una volta calcolato il percorso curvo necessario per raggiungere due punti, possiamo facilmente calcolare la nostra posizione e direzione in un dato istante nel tempo, come mostrato nel Listato 2.
ELENCO 2. Calcolo della posizione e dell'orientamento in un determinato momento.
distance = unit_speed * elapsed_time
loop i = 0 to 3:
if (distance < LineSegment[i].length)
// Unit is somewhere on this line segment
if LineSegment[i] is an arc
//determine current angle on arc (theta) by adding or
//subtracting (distance / r) to the starting angle
//depending on whether turning to the left or right
position.x = LineSegment[i].center.x + r*cos(theta)
position.y = LineSegment[i].center.y + r*sin(theta)
//determine current direction (direction) by adding or
//subtracting 90 to theta, depending on left/right
else
position.x = LineSegment[i].start.x
+ distance * cos(LineSegment[i].line_angle)
position.y = LineSegment[i].start.y
+ distance * sin(LineSegment[i].line_angle)
direction = theta
break out of loop
else
distance = distance - LineSegment[i].length