2016-02-27 35 views
5

在Java中,我正在爲Android編寫一個移動應用程序,用一些我自己編寫的類與一些動態球進行交互。重力取決於手機的傾斜度。物理圈碰撞彈出並滑動邊界

我注意到當我有一堆球團聚在一個角落裏時,他們中的一些會開始抖動,或者有時會在與其他球碰撞時滑動。這可能是因爲我在錯誤的順序執行步驟?

現在我有一個循環遍歷每個球會:

  • 辛迭代
  • 檢查碰撞與其他球
  • 檢查碰撞對現場界

我應該補充說我與邊界發生摩擦,當發生球碰撞時,只是爲了失去能量。

這裏的碰撞是如何被處理的代碼的一部分:

// Sim an iteration 
    for (Ball ball : balls) { 
     ball.gravity.set(gravity.x, gravity.y); 

     if (ball.active) { 
      ball.sim(); 

      // Collide against other balls 
      for (Ball otherBall : balls) { 
       if (ball != otherBall) { 
        double dist = ball.pos.distance(otherBall.pos); 
        boolean isColliding = dist < ball.radius + otherBall.radius; 
        if (isColliding) { 
         // Offset so they aren't touching anymore 
         MVector dif = otherBall.pos.copy(); 
         dif.sub(ball.pos); 
         dif.normalize(); 
         double difValue = dist - (ball.radius + otherBall.radius); 
         dif.mult(difValue); 
         ball.pos.add(dif); 

        // Change this velocity 
        double mag = ball.vel.mag(); 
        MVector newVel = ball.pos.copy(); 
        newVel.sub(otherBall.pos); 
        newVel.normalize(); 
        newVel.mult(mag * 0.9); 
        ball.vel = newVel; 

        // Change other velocity 
        double otherMag = otherBall.vel.mag(); 
        MVector newOtherVel = otherBall.pos.copy(); 
        newOtherVel.sub(ball.pos); 
        newOtherVel.normalize(); 
        newOtherVel.mult(otherMag * 0.9); 
        otherBall.vel = newOtherVel; 
        } 
       } 
      } 
     } 
    } 
+0

我們可以看到你迄今爲止做了什麼嗎? – Dan

+0

你在碰撞測試中測試兩個物體是否相互靠近?你計算確切的碰撞時間還是允許物體相互移動? – LutzL

+0

更新了一些代碼。我不測試兩個物體是否正朝着彼此移動。現在我允許球進入對方,然後處理碰撞。 –

回答

2

如果這是檢查球之間的相互作用的唯一代碼,那麼這個問題似乎很清楚。在平衡狀態下,球沒有辦法在另一個球上休息。

比方說,你有一個球直接在另一個之上。當你計算由於重力引起的頂部球的加速度時,你還應該進行碰撞檢查,就像你發佈的一樣,除了這次檢查dist <= ball.radius + otherBall.radius。如果是這種情況,那麼你應該假設球與球之間的法向力等於重力的大小,並且使連接兩個球的中心的矢量與重力分量相抵消。如果你沒有做到這一點,那麼頂級球將加速到最低點,觸發你發佈的碰撞代碼,你會得到抖動。

當球與場景邊界接觸時,必須使用類似的邏輯。

+0

我想我明白你在做什麼,但我無法計算出碰撞響應。假設我在'ball2'上面有'ball1'。在模擬'ball1'之前,我測試了一下'ball2',看它們是否已經觸摸。如果是,我需要調整'ball1'的位置並調整重力的方向,使它不會穿過它? –

+0

你的位置調整很好,這是你需要調整的重力,因爲它會被兩個球之間的法向力所抵消。因此,如果ball1與ball2接觸,並且ball1的引力(g)與從ball1指向ball2的矢量(v)的矢量點積是正的,那麼您想要從ball1的重力矢量中減去v次(g dot v)/ v^2)。這是重力矢量的方向上的組成部分。 –

1

因爲我一直在試用我自己的Phys2D引擎(只是爲了好玩),我知道你在談論。 (以防萬一 - 您可以在這裏查看我的演示:http://gwt-dynamic-host.appspot.com/ - 選擇「圓形碰撞演示」,並在此處輸入相應的代碼:https://github.com/domax/gwt-dynamic-plugins/tree/master/gwt-dynamic-main/gwt-dynamic-module-bar)。

問題是在迭代和無限循環的碰撞後果的性質。當例如球到達場景的角落時,它會經歷至少3個力的向量:從牆上彈起的衝動,從地面反彈的衝動和重力衝動 - 在總結所有3個衝動後,根據鬆弛能量算法減少它,在你的球應該在哪裏有新的矢量。但是,例如這個衝動將它引導到牆上 - 那麼你必須根據所有的東西重新計算矢量集:反彈的能量,衝動,引力等等。即使在所有這些衝動都很小的情況下,你也永遠不會得到它們全部0 ,因爲雙精度和容差比較常數 - 因爲你有「抖動」和「滑動」效果。實際上,大多數現有的2D引擎都有這樣或那樣的效果:你可能會在這裏看到它們:http://brm.io/matter-js/demo/#wreckingBall或這裏:http://box2d-js.sourceforge.net/index2.html - 它們實際上只是讓小的衝動更快被吸收,並在整個系統變得不再重複或多或少穩定,但並非總是可能。

無論如何,我只是建議不要重新發明自己的車輪,除非它只是爲了你的樂趣 - 或者爲了更好地理解這些東西。

對於最後一個(JFF) - 這裏是很好的教程:http://gamedevelopment.tutsplus.com/tutorials/how-to-create-a-custom-2d-physics-engine-the-basics-and-impulse-resolution--gamedev-6331

對於真正的東西,我建議你使用現有的內燃機,例如Unity(https://unity3d.com/learn/tutorials/modules/beginner/2d/physics2d)或Box2d(http://box2d.org/

希望這會有所幫助。

+0

感謝您的參考!我會開始挖掘他們。 –

1

迭代所有的球並改變每次迭代的球位置可能是導致不穩定的原因,您將一個球左移以避免右邊碰撞,然後您將球推入左邊的另一個球,然後左邊的球試圖再次推回來。

從我的頭頂開始,我可以推薦在做任何關於定位的事情之前總結每個球的所有力量。如果你從「頂部」球(離重力源/方向最遠)迭代球,你可能會達到穩定的狀態。

基本上,頂級球需要先計算自身與其下的球之間的力,再加上重力,那麼下方的球就會知道頂球有多大的力,並且會增加重力也增加了它在它下面推動球的力量。當所有的球知道他們與你一起推動的力量時,可以將這個力量轉化爲運動。

1

你模擬球物理的方式必然會引起不穩定。您的碰撞分辨率會嘗試通過將碰撞深度中的一個投影到相反的方向來分離球。這可能會解決這兩個球的重疊問題,但有可能(特別是當球堆疊時)球現在與另一個球重疊。

修復滲透的方法有很多。最簡單的方法之一是給兩個機構增加一個「偏見」或一點點推動力,迫使他們在接下來的幾幀內分開。這使得能量傳播並強制所有的身體分開。問題是,偏見往往會被高估,並導致一些反彈。要解決這個問題,我建議閱讀順序衝動。

讓物理看起來逼真並不像看起來那麼簡單。除非你不介意不穩定性,否則我建議花一些時間閱讀不同的技術或使用Box2D等引擎。

+0

我同意,我需要推兩者,而不只是一個。不會推兩者仍然有可能與其他球重疊?我想知道我是否應該首先解決最接近邊界的球並朝着中心前進。我會更詳細地閱讀你提到的內容,這似乎非常困難! –

+0

@GreenCell偏見不是投影。這對兩個機構都是一個應用的力量。這意味着當下一次脈衝分辨率通過時,能量會傳播。我假設你正在使用脈衝分辨率。如果你不是,我會建議閱讀它。 – py13579