首先,您需要确定转塔面向方向与目标方向之间的角度差。
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;
一旦获得这些数量,就可以为转塔角度设置第二度表达式。您需要在每次更新时都进行计算,以确保始终使用最新的位置和速度数据。
// Compute angular acceleration.
const float C0 = // Must be determined.
const float C1 = // Must be determined.
float angularAcc = C0 * angleDiff - C1 * turret.angularVelocity;
在此,加速度表达式中的第一个项(零度)将使转塔开始转向目标。但是,它不会及时停止,而是会在其上来回摆动。为了使其停止,我们需要阻尼第二项(一级),该项会使高转弯速度与高加速度相反。
现在,需要确定正常数(不一定是程序常数)并进行平衡,以使系统运行良好。C0
是系统速度的主要控制。较高的值C0
将提供快速的旋转速度,而较低的值将提供较低的旋转速度。实际值取决于许多因素,因此您应在此处使用反复试验。C1
控制阻尼大小。二次方程的判别式告诉我们,如果C1*C1 - 4*C0 >= 0
我们有一个非振动系统。
// New definition.
const float C1 = 2*sqrt(C0); // Stabilizes the system.
C1
出于数字上的原因,您可能应该选择一个比这个大的值,但不要太大,因为它可能会变得过分阻尼并且响应速度很慢。同样,您需要调整。
同样重要的是要注意,该代码仅计算角加速度。需要使用某种形式的积分器从其他地方更新角度和角速度。根据这个问题,我认为已经解决了这一问题。
最后,还有关于滞后的说法,因为在跟踪快速目标时,炮塔可能总是落后。解决此问题的一种简单方法是向目标位置添加线性预测,即始终将目标对准目标的向前方向。
// 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;
/// ...
至于将转塔对准目标半径范围内一段时间,这可能是直接施加于此类系统上的一项艰巨要求。可以肯定的是,该控制器将一直努力将转塔始终对准目标(或预测位置)。如果结果证明不是令人满意,你必须修改参数predictionTime
,C0
以及C1
(稳定的范围内)。