2012-06-13 166 views
1

我正在嘗試編寫一個Java程序來支持離格外擴散有限的融合仿真。用於模擬移動粒子的基本代碼已到位,直到所述粒子碰到靜態中心粒子。在這一點上,我試圖確保移動的粒子剛剛接觸(切線)靜態粒子。但是,由於不明原因,它有時會失敗(8個粒子中的前2個相交,其他6個很好)。圓圈碰撞

下面是代碼:

boolean killed, collide; 
    double xp, yp, dx, dy, theta, xpp, ypp, length; 

    int xc = 200; 
    int yc = 200; 
    int killRadius = 200; 
    int releaseRadius = 150; 
    int partRadius = 14; 
    int partDiam = 2 * partRadius; 

    drawCircle(xc, yc, killRadius); // kill 
    drawCircle(xc, yc, releaseRadius); // release 
    drawCircle(xc, yc, partRadius); // center particle 

    //while (true) { 
     killed = false; 
     collide = false; 

     theta = Math.random() * Math.PI * 2; 
     xp = xc + releaseRadius * Math.cos(theta); 
     yp = yc + releaseRadius * Math.sin(theta); 

     while (true) { 

      theta = Math.random() * Math.PI * 2; 
      length = partDiam; 

      xpp = xp; 
      ypp = yp; 

      xp = xp + length * Math.cos(theta); 
      yp = yp + length * Math.sin(theta); 

      //drawCircle((int) xp, (int) yp, partRadius); 

      // Should it be killed ? (maybe could use a box to fasten 
      // computations... 
      // Would switching the test for kill w test for collision 
      // improve perf ? 
      dx = xp - xc; 
      dy = yp - yc; 
      if ((dx * dx) + (dy * dy) > killRadius * killRadius) { 
       killed = true; 
       break; 
      } 

      // Does it collide with center? replace by any particle... 
      dx = xp - xc; 
      dy = yp - yc; 
      if ((dx * dx) + (dy * dy) < (partDiam) * (partDiam)) { 
       collide = true; 
       break; 
      } 
     } 
// Probably something is wrong here... 
     if (collide) { 
      // no absolute value because particles move at most by diameter 
      double depthPenetration = partDiam 
        - Math.sqrt((dx * dx) + (dy * dy)); 
      dx = xpp - xp; 
      dy = ypp - yp; 
      // shorten distance travelled by penetration length to ensure 
      // that 
      // particle is tangeant 
      length = Math.sqrt((dx * dx) + (dy * dy)) - depthPenetration; 
      xp = xpp + length * Math.cos(theta); 
      yp = ypp + length * Math.sin(theta); 
      drawCircle((int) xp, (int) yp, partRadius); 
     } 
    //} 

當然,我問前檢查許多引用,但不能發現任何錯誤的代碼...幫助將不勝感激。

+2

我調試的代碼太多。我們先從 - 你得到什麼輸出,你期望什麼? – djechlin

+0

如果我是你,我會創建一系列測試計算的單元測試。 –

+0

我不得不承認我仍然很難理解你正在努力完成什麼,而不是你想要解決的問題。什麼是有問題的症狀,你期望什麼,並且你得到了什麼? – trumpetlicks

回答

0

我不認爲我可以調試你的代碼,但是我在很多年前(十多年前)編寫了一些基於java.awt.Shape的碰撞例程,這可能會有所幫助...從這裏檢查ShapeUtils.java :

http://www.cs101.org/psets/breakout/solns/breakout-src.jar

一個你可能有很可能的問題是Java界是連得4分樣條曲線,因此如果你檢查是否所有定義圓點是另一種形狀的內部,你仍然會錯過樣條曲線凸出到其他形狀的情況,但沒有任何點實際在物體內部。我的解決方案(這可能不是不夠好,你的情況是重拍的形狀,直到沿着各自的邊緣點之間的距離比最大可接受誤差較小:

/** 
    * Convert any AWT shape into a shape with a specified precision. 
    * The specified precision indicates the maximum tolerable distance 
    * between knot points. If the shape is already precise enough then 
    * it is returned unmodified. 
    * 
    * @param aShape the shape to be converted if necessary. 
    * @param precision the maximum tolerable distance between knot points. 
    * @return A more precise version of the shape, or the same shape if 
    *   the precision is already satisfied. 
    */ 
    public static Shape getPreciseShape(Shape aShape, float precision) { 

這種精密與模擬的速度沿對象,告訴我在模擬中我必須檢查碰撞(最大增量時間)的頻率......如果您不縮放時間間隔,快速移動的模擬對象可以在一個時間間隔內通過固體對象拉鍊少於所需精度的時間

基本上這樣就成了計算成本和結果精度之間的直接折衷。我只是希望遊戲看起來不錯,所以我只需要非常精確以確保物體不會重疊超過半個像素左右。

編輯:讓我總結一下我的建議......在重新閱讀我知道我得到了在細節丟失,從來沒有設法指出關鍵的概念... Java有很多,對於工作得非常好例程測試Shape的各種實現(包括圓圈)。我的建議是儘可能使用java庫,並獲得可以驗證的結果是否正確。一旦你有了用於檢查代碼工作的代碼和方法,如果你需要更多的速度,開始優化它的一部分,最好在分析正在運行的程序(產生正確的結果)之後,看看哪些部分會限制你的性能。

1

我通過代碼做了一些簡單的重構,只是爲了感受它的作用,發生了什麼。

讓我在開始時提到一件事:這是Sphaghetti怪獸的復興,不是嗎?你喜歡全局變量嗎? Long,superpotent 讓我們現在就做,現在這裏 methoods?

如果您儘可能晚地引入變量,那麼您的代碼的讀者不需要向上搜索,此變量之前的內容 - 例如,如果重寫了某個變量,例如,是否存在重複使用。

如果你的變量不改變:使它們最終。這簡化了對他們的推理。final int killRadius = 200;表示獲得類型信息和價值,並希望在第一次使用之前不久,並且永遠不會改變。僅在源代碼中配置。可能不是一個太複雜的候選人。相較於雙DX - 未初始化,因爲它得到的內環路初始化,

static void foo() { 

    final int xc = 200; 
    final int yc = 200; 
    final int killRadius = 200; 
    final int releaseRadius = 150; 
    final int partRadius = 14; 

    drawCircle (xc, yc, killRadius); // kill 
    drawCircle (xc, yc, releaseRadius); // release 
    drawCircle (xc, yc, partRadius); // center particle 

    //while (true) { 
    boolean killed = false; 
    boolean collide = false; 

    double theta = Math.random() * Math.PI * 2;  
    double xp = xc + releaseRadius * Math.cos (theta); 
    double yp = yc + releaseRadius * Math.sin (theta); 
    double dx, dy, xpp, ypp; 

    while (true) { 

     theta = Math.random() * Math.PI * 2; 
     final int partDiam = 2 * partRadius; 
     final double length = partDiam; 

     xpp = xp; 
     ypp = yp; 

     xp += length * Math.cos (theta); 
     yp += length * Math.sin (theta); 

     dx = xp - xc; 
     dy = yp - yc; 
     if ((dx * dx) + (dy * dy) > killRadius * killRadius) { 
      killed = true; 
      break; 
     } 

     // Why again assign dx = xp -xc? Did any of these values change meanwhile? 
     // I don't think so. 
     // dx = xp - xc; 
     // dy = yp - yc; 
     if ((dx * dx) + (dy * dy) < (partDiam) * (partDiam)) { 
      collide = true; 
      break; 
     } 
    } 
    if (collide) { 
     // no absolute value because particles move at most by diameter 
     double depthPenetration = partDiam - Math.sqrt((dx * dx) + (dy * dy)); 
     dx = xpp - xp; 
     dy = ypp - yp; 
     // shorten distance travelled by penetration length to ensure 
     // that 
     // particle is tangeant 
     final double length = Math.sqrt((dx * dx) + (dy * dy)) - depthPenetration; 
     xp = xpp + length * Math.cos (theta); 
     yp = ypp + length * Math.sin (theta); 
     drawCircle ((int) xp, (int) yp, partRadius); 
    } 

如果你組織你這樣的代碼,你不僅可以看到,像XC一定的價值是200和從未改變 - 在while循環的頭部,你會發現theta沒有在循環中聲明,所以無論是稍後在循環外使用,還是在循環內部依次修改。做一個x + = 4;您無法在循環傳球中初始化x。

在大而結束,你有兩個類似的塊:

dx = xp - xc; 
    dy = yp - yc; 
    if ((dx * dx) + (dy * dy) (OP) a OP b) { 
     c = true; 
     break; 
    } 

但XP,XC和DX不同時改變 - 也不在y當量。這是一個錯誤,還是爲什麼你再次分配它們?

然後,你可以通過這種方式擺脫你的無盡:既然這兩個條件終止了while,把條件放到while - test中,並且調用第二個block(不重複賦值),只有當第一個wasn'牛逼進入 - 關鍵字這樣做是else

while (!killed && !collide) { 

     // ... 

     dx = xp - xc; 
     dy = yp - yc; 
     if ((dx * dx) + (dy * dy) > killRadius * killRadius) { 
      killed = true; 
     } 
     else if ((dx * dx) + (dy * dy) < (partDiam) * (partDiam)) { 
      collide = true; 
     } 
    } 

是什麼在發現錯誤幫助嗎?沒那麼多。如果兩個圈子被錯誤地放置,其餘的都很好,屏幕截圖將會很好,並且值會導致不良的圈子,並且這些值是正確的。