2014-07-14 29 views
2

所以我在JSFiddle中建立了一個小的重力模擬。這是我的腳本到目前爲止:對象在重力模擬中緩慢漂移到右邊

var elements = [ 
    { 
     "id": "earth", 
     "mass": 30, 
     "left": 30, 
     "top": 30, 
     "hSpeed": 300, 
     "vSpeed": -300 
    }, { 
     "id": "sun", 
     "mass": 5000, 
     "left": 50, 
     "top": 50, 
     "hSpeed": 0, 
     "vSpeed": 0 
    }]; 

var intervalTime = 10; 

var intervalID; 

var getDistance = function(x1, y1, x2, y2) { 

    // h^2 = x^2 + y^2 

    var xD = x1 - x2; 
    var yD = y1 - y2; 
    var hSq = xD * xD + yD * yD; 

    return Math.sqrt(hSq); 
}; 

var getXPortion = function(val, x1, y1, x2, y2) { 

    var hD = getDistance(x1, y1, x2, y2); 
    var xD = x2 - x1; 

    if ((hD == 0) || (xD == 0) || (val == 0)) { 
     return 0; 
    } 

    return val/hD * xD; 
}; 

var getYPortion = function(val, x1, y1, x2, y2) { 

    var hD = getDistance(x1, y1, x2, y2); 
    var yD = y2 - y1; 

    if ((hD == 0) || (yD == 0) || (val == 0)) { 
     return 0; 
    } 

    return val/hD * yD; 
}; 

var animateWorld = function() { 

    // Calculate the change in speed for each element 
    // based on the gravity of all the other elements 
    var i = 0; 
    var j = 0; 
    var dist = 0; 
    var mass = 0; 
    var grav = 0; 
    var change = 0; 
    var chX = 0; 
    var chY = 0; 
    for (i in elements) { 
     for (j in elements) { 
      if (i != j) { 
       dist = getDistance(
        elements[i].left, 
        elements[i].top, 
        elements[j].left, 
        elements[j].top 
       ); 
       mass = elements[i].mass * elements[j].mass; 
       grav = dist == 0 ? 0 : mass/(dist * dist); 
       change = grav/elements[i].mass; 
       elements[i].hSpeed += getXPortion(
        change, 
        elements[i].left, 
        elements[i].top, 
        elements[j].left, 
        elements[j].top 
       ); 
       elements[i].vSpeed += getYPortion(
        change, 
        elements[i].left, 
        elements[i].top, 
        elements[j].left, 
        elements[j].top 
       ); 
      } 
     } 
    } 

    // Calculate the new position for each element 
    // based on the speed and move each element to it's new position 
    for (i in elements) { 
     elements[i].left += elements[i].hSpeed/1000; 
     elements[i].top += elements[i].vSpeed/1000; 
     $('#' + elements[i].id).css('left', elements[i].left + '%'); 
     $('#' + elements[i].id).css('top', elements[i].top + '%'); 
    } 

}; 

$(document).ready(function() { 
    intervalID = window.setInterval(animateWorld, intervalTime); 
}); 

我允許所有的對象根據各自的質量和距離相互作用。問題是所有的物體都緩慢地向右漂移。由於這是一個封閉的系統,我認爲只有當另一個基於質量向左移動時,纔會向右移動,所以它們應該不可能隨着時間的推移沿同一方向漂移。我認爲正在發生的下列之一,但我不知道其中:

  1. 在數學中使用浮動點造成導致這種(不太可能)
  2. 的,我第一次計算,情況略有四捨五入問題每個身體對另一個身體的影響,然後移動他們造成一些偏見。我是這樣的,我該如何解決它?

任何想法?有沒有更簡單的方法來做到這一點?

+0

在第一次看,它看起來像太陽只漂移的權利,但沒有離開,也許這會幫助調試過程 –

+1

你的大地似乎對你的太陽相當大的影響。在開始時將地球的位置改變到右上角,並改變速度向左下方發射,使其反向運行,太陽開始以另一種方式移動 – AeroX

+0

@AeroX。我並沒有試圖建立一個真實的尺度,只是一個逼真的模擬引力效應,不管潛在的假設如何 – neelsg

回答

2

我認爲這是你的#2的可能性。

您應該避免循環遍歷對象並逐個應用一個部件。這意味着模擬的行爲會有所不同,具體取決於數組中對象的順序,這不應該發生。

我會建議爲每個對象添加更多的字段,包括'hAcceleration'和'vAcceleration'。遍歷所有對象並計算每個對象的重力加速度。

然後,遍歷所有對象,加速到速度。然後,再次循環,將速度添加到位置。這就是我過去所做的,似乎運作良好。

+0

實際上不僅僅是這樣。我按照你的建議,只是在計算所有物體的速度後才更新速度。漂移速度較慢,但​​仍然存在[JSFiddle](http://jsfiddle.net/neelsg/5nwsS/16/) – neelsg

0

您正在使用整數類型。分割整數必須在最後一步完成。您所做的每個部門都會導致信息丟失較小,因爲結果必須轉換爲整數。 嘗試使用雙精度型而不是整型對所有操作進行操作,並且僅當您將新位置設置爲您的元素時才投射。任何其他計算必須保持雙倍。

將1.0乘以一個操作數(即將其轉換爲double)將會有所幫助。所以你可以做這樣的事情:

return val * 1.0/hD * xD; 

其中返回未開放的未周旋的雙。

+0

不是這樣。我根據你的建議修改了它,它仍然漂移[JSFiddle](http://jsfiddle.net/neelsg/5nwsS/11/) – neelsg

+0

我並不是僅僅意味着這一行。您必須保持所有數據都是雙倍數據,設置新位置,並根據雙數據計算下一個數據,而不是計算新整數位置。 – AHH

+0

感謝您的反饋,但是如果您看小提琴,您會看到我爲每個相關線路都做了它 – neelsg

2

實際上有一個問題是@kbelder說的,但另一個問題是我的物理疏忽,如在JSFiddle中修復的那樣。問題是我給一個物體(地球)一個速度(即動量),另一個(太陽)沒有補償動量,所以整個團隊的動力很小。請注意0​​和"vSpeed": 1.8值爲「陽光」進行補償。

var elements = [ 
    { 
     "id": "earth", 
     "mass": 30.0, 
     "left": 30.0, 
     "top": 30.0, 
     "hSpeed": 300.0, 
     "vSpeed": -300.0 
    }, { 
     "id": "sun", 
     "mass": 5000.0, 
     "left": 50.0, 
     "top": 50.0, 
     "hSpeed": -1.8, 
     "vSpeed": 1.8 
    }];