程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Robocode高手的秘訣 - 圓周瞄准

Robocode高手的秘訣 - 圓周瞄准

編輯:關於JAVA

這篇小技巧會讓您深入理解圓周瞄准的工作原理。我們會從討論基本技巧的工作原理開始,接著闡釋一個簡單的迭代,它能顯著提高准確性。我還提供 源 代碼,它很容易適應在您自己的機器人中工作。

工作原理

計算做圓周運動的機器人的 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 有規律的目標。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved