2013-04-22 15 views
1

我在球之間的碰撞分辨率方面存在問題。 其實碰撞反應非常現實,但動力不守恆,爲什麼?在球之間的碰撞分辨率之後,動量不守恆

我使用基於此文件的算法:http://www.vobarian.com/collisions/2dcollisions2.pdf

在Java代碼中我的算法是:

/** 
* Resolve the collision creating new velocities according to physical laws. 
*/ 
public void resolveCollisionWith(Ball ball) { 
    //First resolve intersection for calculate correct new velocities. 
    resolveIntersectionWith(ball); 

    //Unit normal vector uN is the unit-vector that links the two centers. 
    Vector uN = mPosition.subtraction(ball.getPosition()).normalize(); 

    //Unit tangent vector uT is the unit-vector normal to uN. It's tangent to both the two balls. 
    Vector uT = new Vector(-uN.getY(), uN.getX()); 

    //Project the two balls velocities onto the collision axis(uT and uN vectors). 
    double v1n = uN.dot(mVelocity), v1t = uT.dot(mVelocity); 
    double v2n = uN.dot(ball.getVelocity()), v2t = uT.dot(ball.getVelocity()); 

    //Calculate the post collision normal velocities (tangent velocities don't change). 
    double v1nPost = (v1n*(mMass-ball.getMass()) + 2*ball.getMass()*v2n)/(mMass+ball.getMass()); 
    double v2nPost = (v2n*(ball.getMass()-mMass) + 2*mMass*v1n)/(mMass+ball.getMass()); 

    //Convert scalar velocities to vectors. 
    Vector postV1N = uN.multiplication(v1nPost), postV1T = uT.multiplication(v1t); 
    Vector postV2N = uN.multiplication(v2nPost), postV2T = uT.multiplication(v2t); 

    //Change the balls velocities. 
    mVelocity.set(postV1N.addition(postV1T)); 
    ball.getVelocity().set(postV2N.addition(postV2T)); 
} 

/** 
* When two balls collide can occur an intersection(the distance between the centers 
* is less than the sum of the radii) that dephases the response. 
* The method fix this situation bringing back the two ball according to their mass. 
*/ 
private void resolveIntersectionWith(Ball ball){ 
    Vector n = mPosition.subtraction(ball.getPosition()); 
    // How much the distance between centers is less than the radii's sum. 
    double offset = getRadius() + ball.getRadius() - n.length(); 
    n.normalize(); 
    n.multiply(offset); 
    // Bring back the two ball according to their mass. 
    mPosition.add(n.multiplication(ball.getMass() * 1.0/(mMass + ball.getMass()))); 
    ball.getPosition().subtract(n.multiplication(mMass * 1.0/(mMass + ball.getMass()))); 
} 

/** 
* Normalizes and returns this vector. 
*/ 
// ***INSIDE VECTOR CLASS*** 
public Vector normalize() { 
    //Avoid division by zero. 
    if (mX != 0 || mY != 0) { 
     double lenght = length(); 
     mX /= lenght; 
     mY /= lenght; 
    } 
    return this; 
} 

謝謝!

+0

「勢頭不守恆」是什麼意思?球慢下來?加速? – 2013-04-22 16:53:26

+0

當動量守恆時:m1 * v1 + m2 * v2 = m1 * v1'+ m2 * v2'(m1是第一個球的質量,v1是碰撞前的速度,v1是碰撞後的速度) – VanDir 2013-04-22 16:58:00

+0

發表'resolveIntersectionWith'? – Antimony 2013-04-22 16:59:36

回答

2

假設準確的數學方程,方程本身將會對衝動量。所以自然的嫌疑犯是浮點錯誤。在正常情況下,這些錯誤將會非常小,儘管它們仍然會隨着時間累積。但是,通過小數分割可以放大錯誤。

標準化一個非常小的矢量時,由於每個組件的劃分中有放大的錯誤,最終可能會出現幅度不接近1的情況。這反過來將大大改變勢頭。事實上,你的代碼編寫的方式可以給你無限或NaN,但我認爲你會注意到,如果是這樣的話。實際上,在某些情況下,甚至根本沒有對矢量進行歸一化(當兩個組件完全爲0時)。但你仍然盲目地繼續僞造矢量。

編輯:我只是注意到你的向量是可變的。我強烈建議讓它們不可變。它簡化了代碼並減少了缺失副本的缺陷範圍。

+0

這是一個愚蠢的錯誤。謝謝。 – VanDir 2013-04-22 17:22:38

+0

關於問題:在你看來可以改變一些使用float而不是double的東西嗎?在這個問題http://stackoverflow.com/questions/5008252/2d-ball-collision-problem-no-conservation-of-energy?rq=1用戶申明使用相同的算法獲得動量守恆(用float )... – VanDir 2013-04-22 17:28:34

+0

更改爲浮動只會使錯誤更大。 – Antimony 2013-04-22 17:29:11

1

我有一個類似的問題與我的程序,我有一個用戶定義數量的球隨機質量,半徑和速度不斷相互碰撞。由於小數舍入錯誤而產生問題,這是不可避免的。

我想這其中的解決方案,更讓我一貫的勢頭加上或減去內的起始勢頭約1%,是因爲:

建立一個叫做firstRun布爾,和兩個雙打totalMomentum和totalMomentum2。計算循環中第一次運行的總動量並將其保存到totalMomentum。然後,每隔一次運行,計算總動量並將其保存到totalMomentum2。

然後,對於第一次之後的每次跑步,將球的速度乘以比率(totalMomentum/totalMomentum2)。

這樣,如果動量太高,它會使總量更低。如果它太低,它會使它更高。

我有一個安裝程序,當前有200個球與彼此碰撞,初始動量約爲45000.我的範圍始終保持在44500和45500之間。

希望這會有所幫助!

編輯:當我把球的數量減少到5,並增加質量,總動量約爲22500時,使用這種方法的動量幾乎完美保存。大部分時間都不會發生波動,如果是這樣,它會從22500上漲到22499,然後回到22500.