Tracciamento target: quando accelerare e decelerare una torretta rotante?


24

Supponiamo che abbia una circolare mobile targetdefinita come:

Vector2 position;
Vector2 velocity;
float radius;

E un rotante turret(montato su un veicolo in movimento di qualche tipo) definito come:

Vector2 position;
Vector2 velocity;
float angle; // radians
float angularVelocity; // radians per second
const float maxAngularVelocity; // radians per second
const float maxAngularAcceleration; // radians per second per second

(O qualcosa del genere. Nota che la posizione e la velocità di entrambi sono controllate altrove - supponiamo che la velocità sia costante e la posizione cambia in base alla velocità.)

Sto cercando di scrivere due funzioni AI correlate per determinare, su un determinato frame:

  • Quale accelerazione angolare (e in quale direzione) applicare all'angolo della torretta per mantenere la torretta puntata sul bersaglio?

  • Se il bersaglio è attualmente in vista, può (qualsiasi parte nel suo raggio) essere tenuto in vista per xsecondi, dov'è xuna frazione di secondo? (In alternativa: esiste un'altra strategia per garantire che l'obiettivo sia effettivamente "bloccato" e non semplicemente volando attraverso le attrazioni?)

E potrei usare un po 'd'aiuto ...


1
Potresti avere valori diversi per l'accelerazione e la decelerazione rotazionale: nel mondo reale, uno probabilmente è un motore e l'altro un freno.
e100

Risposte:


19

Per prima cosa devi determinare la differenza di angolo tra la direzione della torretta e la direzione rispetto al bersaglio.

Vector2 turretToTarget = target.position - turret.position;
float desiredAngle = atan2(turretToTarget.y, turretToTarget.x);
float angleDiff = desiredAngle - turret.angle;

// Normalize angle to [-PI,PI] range. This ensures that the turret
// turns the shortest way.
while (angleDiff < -PI) angleDiff += 2*PI;
while (angleDiff >= PI) angleDiff -= 2*PI;

Una volta che hai queste quantità, puoi impostare un'espressione di secondo grado per l'angolo della torretta. È necessario calcolare questo su ogni aggiornamento per assicurarsi di utilizzare sempre i dati più recenti di posizioni e velocità.

// Compute angular acceleration.
const float C0 = // Must be determined.
const float C1 = // Must be determined.
float angularAcc = C0 * angleDiff - C1 * turret.angularVelocity;

Qui, il primo termine (zero gradi) nell'espressione di accelerazione farà sì che la torretta inizi a girare verso il bersaglio. Tuttavia non si fermerà nel tempo, ma piuttosto oscillerà avanti e indietro su di esso. Per fermarlo abbiamo bisogno del secondo termine di smorzamento (primo grado) che fa sì che un'alta velocità di rotazione sia contrastata da un'alta accelerazione.

Ora le costanti positive (non necessariamente le costanti del programma) devono essere determinate ed equilibrate per far funzionare bene il sistema. C0è il principale controllo per la velocità del sistema. Un valore alto per C0darà una velocità di virata veloce e un valore basso darà una velocità di sterzata bassa. Il valore effettivo dipende da molti fattori, quindi è necessario utilizzare tentativi ed errori qui. C1controlla la grandezza di smorzamento. Il discriminante dell'equazione quadratica ci dice che se C1*C1 - 4*C0 >= 0abbiamo un sistema non oscillante.

// New definition.
const float C1 = 2*sqrt(C0); // Stabilizes the system.

Probabilmente dovresti scegliere C1un po 'più grande di questo per motivi numerici, ma non troppo grande perché potrebbe invece essere molto smorzato e rallentare la risposta. Ancora una volta, è necessario modificare.

Inoltre, è importante notare che questo codice calcola solo l'accelerazione angolare. L'angolo e la velocità angolare devono essere aggiornati da questo altrove, utilizzando e integratore di qualche tipo. Dalla domanda presumo che questo sia stato coperto.

Infine c'è qualcosa da dire sul ritardo, perché probabilmente la torretta sarà sempre dietro quando seguirà un bersaglio veloce. Un modo semplice per affrontarlo è aggiungere una previsione lineare alla posizione del bersaglio, cioè puntare sempre leggermente in avanti nella direzione in avanti del bersaglio.

// Improvement of the first lines above.
const float predictionTime = 1; // One second prediction, you need to experiment.
Vector2 turretToTarget = target.position + predictionTime * target.velocity - turret.position;
/// ...

Per quanto riguarda il mantenimento della torretta puntata nel raggio del bersaglio per qualche tempo, questo può essere un duro requisito da imporre direttamente su questo tipo di sistema. Puoi essere certo che questo controller si impegnerà a mantenere la torretta puntata sul bersaglio (o meglio sulla posizione prevista) in ogni momento. Se il risultato risulta non soddisfacente è necessario modificare i parametri predictionTime, C0e C1(entro certi limiti stabili).


Non sono qualificato per dire se questo è giusto o no, ma suona come roba intelligente! In passato ho risolto questo tipo di problemi prevedendo l'effetto dell'accelerazione per capire quando accelerare e quando "applicare le interruzioni". Significa che ho sbagliato?
Iain,

L'atan2 rende difficile l'adattamento di questo metodo a un sistema predittivo poiché i parametri xey di atan2 diventano dipendenti da t.
Skizz,

Questa è esattamente la soluzione a cui ho accennato nella mia risposta di seguito. Dettagli e presentazione eccellenti!
drxzcl,

@Iain: No, non c'è giusto o sbagliato qui. Mentre immagino che il tuo metodo avrebbe due stati discreti: accelerare / decelerare, questo metodo è ispirato da un regolatore della teoria del controllo, ridimensionando l'accelerazione per fare una risposta rapida riducendo al contempo il superamento e le oscillazioni.
Staffan E

1
Come per gli altri commenti, questo funzionerà per un bersaglio fermo ma probabilmente sarà inaccettabile per qualsiasi bersaglio in movimento. I termini C0 e C1 sono roba di molla smorzata tradizionale, in cui C0 rappresenta la forza della molla (di solito chiamata k) e C1 è il fattore di smorzamento (di solito chiamata 'B' o 'c'). Quindi sì, puoi minimizzare le oscillazioni aumentando lo smorzamento, ma il problema è che questo non tenta di anticipare dove sarà il bersaglio , quindi è condannato a ritardare l'obiettivo desiderato.
dash-tom-bang,

3

Quello che hai qui è un problema di controllo di base . La torretta è il sistema, l'accelerazione è il controllo e il sensore misura la posizione / velocità. Esistono molti modi per affrontare questi problemi, poiché si tratta di un problema molto ben studiato in ingegneria.

Key sta finendo con un sistema stabile, cioè un sistema che non genera oscillazioni. Questo di solito viene fatto aggiungendo smorzamento. La pagina di Wikipedia dovrebbe iniziare.


2

Prima di tutto, calcola il vettore dalla torretta al bersaglio. Quindi confronta questo con il vettore corrente della torretta. Quindi utilizzare la differenza tra i due per calcolare l'accelerazione angolare e la velocità angolare necessarie per far girare la torretta per puntare nella giusta direzione entro un determinato tempo.

OK, sembrava semplice. Tuttavia, dovresti davvero provare ad anticipare la posizione del bersaglio poiché il bersaglio si muoverà quando girerai la torretta. Per farlo:-

Pd' = Pd + t.Vd
Ps' = Ps + t.Vs

dove P è posizione e V è velocità e il pedice è d per destinazione (target) e s per sorgente (torretta), che fornisce un vettore di direzione: -

Dsd' = Pd' - Ps' = Pd + t.Vd - (Ps + t.Vs) = Pd - Ps + (Vd - Vs).t

dove D è un vettore di direzione e Dsd 'è la direzione richiesta al tempo t. Ora, calcola la direzione della torretta in base alla posizione attuale e alla massima velocità e accelerazione per un dato tempo t: -

Ds' = t.Ds.Rs -> this is a vector rotation

Ds e Ds 'sono le direzioni della sorgente e Rs è la velocità di rotazione. Con tutto ciò, vuoi trovare t per quando Dsd '== Ds' e quindi Rs, la velocità di rotazione richiesta. Non dimenticare che tutte le P, le D e le V hanno componenti x e y.

Non ho preso in considerazione l'accelerazione qui - questo aggiunge molto di più alla complessità. Una volta che hai Rs e t potresti probabilmente approssimare un R parabolico (cioè accelerare e decelerare) per ottenere lo stesso risultato.


Questa sembra una buona risposta per il calcolo dell'intercettazione, ma sfortunatamente c'è un grande divario tra le persone che possono leggere quel tipo di notazione matematica e trasformarlo in codice del programma, e la maggior parte delle persone che creano giochi che non conoscono già la risposta a la domanda. In altre parole, penso che gli sviluppatori del gioco siano in grado di leggere quella notazione matematica, probabilmente già possono capire come programmare la soluzione di sparo. Mi aiuterebbe a capire le tue formule se spiegassi cosa significano i tuoi termini.
Dronz,

2

Quello che probabilmente stai cercando qui è un controller PID , simile alla risposta accettata su questa domanda SO

Inizialmente avevo risposto a questa domanda "realizzando il mio", ma questa risposta è significativamente più completa ed elegante.


0

La prima cosa da fare è calcolare l'angolo tra l'oggetto corrente e quello tracciato.
La prossima cosa è verificare se usando l'attuale velocità del torrent e applicando la massima accelerazione all'indietro (arrestando il torrent) il torrent si fermerà prima o dopo l'oggetto tracciato.
Se la risposta è che il torrent si fermerà prima dell'oggetto tracciato, applica la massima accelerazione in avanti (velocità crescente).
Se la risposta è che il torrent si fermerà dopo l'oggetto tracciato, applica la massima accelerazione all'indietro (arrestando il torrent).
In questo modo il torrent arriverà sempre il più veloce e si fermerà al punto giusto (o una frazione dopo).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.