Primero debe determinar la diferencia de ángulo entre la dirección de la torreta y la dirección del objetivo.
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 vez que tenga estas cantidades, puede configurar una expresión de segundo grado para el ángulo de la torreta. Debe calcular esto en cada actualización para asegurarse de utilizar siempre los últimos datos de posiciones y velocidades.
// Compute angular acceleration.
const float C0 = // Must be determined.
const float C1 = // Must be determined.
float angularAcc = C0 * angleDiff - C1 * turret.angularVelocity;
Aquí, el primer término (grado cero) en la expresión de aceleración hará que la torreta comience a girar hacia el objetivo. Sin embargo, no se detendrá a tiempo sino que oscilará de un lado a otro. Para detenerlo, necesitamos el segundo término de amortiguación (primer grado) que hace que una alta velocidad de giro se oponga por una alta aceleración.
Ahora las constantes positivas (no necesariamente las constantes del programa) deben determinarse y equilibrarse para que el sistema se comporte bien. C0
es el mayor control para la velocidad del sistema. Un valor alto para C0
dará una velocidad de giro rápida y un valor bajo dará una velocidad de giro baja. El valor real depende de muchos factores, por lo que debe usar prueba y error aquí. C1
controla la magnitud de la amortiguación. El discriminante de la ecuación cuadrática nos dice que si C1*C1 - 4*C0 >= 0
tenemos un sistema no oscilante.
// New definition.
const float C1 = 2*sqrt(C0); // Stabilizes the system.
Probablemente debería elegir C1
un poco más grande que esto por razones numéricas, pero no demasiado grande, ya que en su lugar se puede amortiguar demasiado y responder lentamente. Nuevamente, necesitas modificar.
También es importante tener en cuenta que este código solo calcula la aceleración angular. El ángulo y la velocidad angular deben actualizarse a partir de esto en otro lugar, utilizando un integrador de algún tipo. De la pregunta asumo que esto ha sido cubierto.
Finalmente, hay algo que decir sobre el retraso, porque la torreta probablemente siempre estará detrás cuando se rastrea un objetivo rápido. Una manera simple de abordar esto es agregar una predicción lineal a la posición del objetivo, es decir, siempre apunte un poco hacia adelante en la dirección hacia adelante del objetivo.
// 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;
/// ...
En cuanto a mantener la torreta apuntada dentro del radio del objetivo durante algún tiempo, este puede ser un requisito difícil de imponer directamente en este tipo de sistema. Puede estar seguro de que este controlador se esforzará por mantener la torreta apuntada al objetivo (o más bien la posición predicha) en todo momento. Si el resultado resulta no ser satisfactoria tiene que modificar los parámetros predictionTime
, C0
y C1
(dentro de ciertos límites estables).