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 C0
darà 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. C1
controlla la grandezza di smorzamento. Il discriminante dell'equazione quadratica ci dice che se C1*C1 - 4*C0 >= 0
abbiamo un sistema non oscillante.
// New definition.
const float C1 = 2*sqrt(C0); // Stabilizes the system.
Probabilmente dovresti scegliere C1
un 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
, C0
e C1
(entro certi limiti stabili).