這篇小技巧會讓您深入理解圓周瞄准的工作原理。我們會從討論基本技巧的工作原理開始,接著闡釋一個簡單的迭代,它能顯著提高准確性。我還提供 源 代碼,它很容易適應在您自己的機器人中工作。
工作原理
計算做圓周運動的機器人的 change in x(x 方向上的變化)和 change in y(y 方向上的變化)的偽碼相當簡單,假定您以弧度為單位進行計算:
change in x = cos(initialheading) * radius - cos(initialheading + changeinheading) * radius
change in y = sin(initialheading + changeinheading) * radius - sin (initialheading) * radius
式中 initialheading是敵方機器人在初始位置的方向,子彈飛行期間的方向 變化為 changeinheading,我們假定它以 radius為圓周半徑運動。
計算必要的數據
圖 1 說明了我們需要的大部分數據: r是機器人運動所繞的圓周半徑,方向 變化為 a,而 v則是敵方機器人運動的即時速度。
圖 1. 沿圓周移動
為了要准確瞄准敵人,我們需要某些特定的數據:機器人當前的方向,每轉 的方向變化,當前的速度,我們的子彈到達的時刻。我們可以使用這些數據計算 出敵人轉圈的圓半徑,以及它最後的方向(即,我們的子彈到達敵人的瞬間敵人 的方向)。我們計算子彈擊中位置的方法如下:
每轉的方向變化:我們用 headingchangeperturn = (heading2 - heading1)/time 得到這個值,其中 time是兩次測量的間隔時間。您還必須使結 果標准化,如下面代碼中所示。
子彈時間:我們使用簡單的 time = getTime()+(range/(20- (3*firepower))) 就可以滿足需要了。其中 range是發射時我們和敵人之間的距 離,而 firepower是我們計劃使用的射擊火力。假定子彈擊中時,目標到我方的 距離不變,這個假設並不合適,但是我們在本文後面的內容中開發出迭代之前, 有它就足夠了。
半徑:我們用 radius = velocity/headingchangeperturn 得出這個值。
代碼
圓周路徑預測只需要清單 1。但是,請注意如果目標的方向變化很小,那麼 就要使用直線瞄准。由於一旦半徑過大將導致存儲它所用的 double 溢出,因而 我們使用這種方式來緩解這一風險。不過條件是方向變化比較小,我們也就不必 太擔心了。
清單 1. 圓周瞄准代碼
public Point2D.Double guessPosition(long when) {
/**time is when our scan data was produced. when is the time
that we think the bullet will reach the target. diff is the
difference between the two **/
double diff = when - time;
double newX, newY;
/**if there is a significant change in heading, use circular
path prediction**/
if (Math.abs(changehead) > 0.00001) {
double radius = speed/changehead;
double tothead = diff * changehead;
newY = y + (Math.sin(heading + tothead) * radius) -
(Math.sin(heading) * radius);
newX = x + (Math.cos(heading) * radius) -
(Math.cos(heading + tothead) * radius);
}
/**if the change in heading is insignificant, use linear
path prediction**/
else {
newY = y + Math.cos(heading) * speed * diff;
newX = x + Math.sin(heading) * speed * diff;
}
return new Point2D.Double(newX, newY);
}
改進結果
如果您已經試過清單 1 中的代碼,那麼您會發現對付 spinbot(沿圓周移動 的樣本機器人)的情況明顯好多了,但您很可能還會注意到,機器人發出的炮彈 中仍有不少沒有命中目標。這不單單是因為瞄的不准;還要歸因於您對子彈要花 費多長時間才能到達目標的估算不准。要提高您的技術,可以通過使用一個非常 簡單的迭代來估算一下時間,然後把這個估算值送入瞄准系統得到當子彈到達目 標時您與目標之間的距離的更精確的估算值。反復執行幾次這一步,您將得到近 乎完美的估值。
清單 2. 迭代代碼
/**This function predicts the time of the intersection between the
bullet and the target based on a simple iteration. It then moves
the gun to the correct angle to fire on the target.**/
void doGun() {
long time;
long nextTime;
Point2D.Double p;
p = new Point2D.Double(target.x, target.y);
for (int i = 0; i < 10; i++){
nextTime =
(intMath.round((getRange(getX(),getY(),p.x,p.y)/(20- (3*firePower))));
time = getTime() + nextTime;
p = target.guessPosition(time);
}
/**Turn the gun to the correct angle**/
double gunOffset = getGunHeadingRadians() -
(Math.PI/2 - Math.atan2(p.y - getY(), p.x - getX()));
setTurnGunLeftRadians(normaliseBearing(gunOffset));
}
double normaliseBearing(double ang) {
if (ang > Math.PI)
ang -= 2*PI;
if (ang < -Math.PI)
ang += 2*Math.PI;
return ang;
}
public double getrange(double x1,double y1, double x2,double y2) {
double x = x2-x1;
double y = y2-y1;
double h = Math.sqrt( x*x + y*y );
return h;
}
改進圓周瞄准的性能
作為瞄准系統,圓周瞄准基本成形了;也就是說,既在我們能力所及范圍內 又能在此基礎上更進一步的事並不多。但是,能改善性能的小改動有兩處:
平均速度:您也許願意保持一個補償加速效應的移動平平均速度,而不是根 據目標的最後速度進行計算。
每一回合方向的平均變化:測量在每一回合內目標方向變化絕對量的平均值 有助於我們對付那些不如 spinbot 有規律的目標。