物体在重力模拟中缓慢向右漂移

时间:2014-07-14 15:58:13

标签: javascript animation math simulation

所以我在 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. 的次要舍入问题
  3. 我首先计算每个身体对另一个身体的影响然后移动它们的事实导致一些偏见。我就是这样,我应该怎么解决它?
  4. 有什么想法吗?有更简单的方法吗?

3 个答案:

答案 0 :(得分:2)

我认为这是你的第二种可能性。

您应该避免循环浏览对象并一次施加一个力。这意味着模拟的行为会有所不同,具体取决于数组中对象的顺序,这不应该发生。

我建议为每个对象添加一些字段,包括' hAcceleration'和' vAcceleration'。循环遍历所有对象并计算每个对象的重力加速度。

然后,循环遍历所有物体,将加速度添加到速度上。然后,再次循环,将速度添加到位置。这就是我过去做过的事情,而且它似乎运作良好。

答案 1 :(得分:2)

实际上有一个问题是@kbelder所说的,但另一个问题是我在 JSFiddle 中修复的物理疏忽。问题是我给了一个物体(地球)一个速度(即动量)而另一个物体(太阳)没有补偿动量,因此整个群体的动量很小。请注意" sun"的"hSpeed": -1.8"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
    }];

答案 2 :(得分:0)

您正在使用整数类型。必须在最后一步完成除分整数。您执行的每个分区都会导致信息丢失,因为结果必须转换为整数。 尝试将所有操作设置为double类型而不是整数,并仅在将新位置设置为元素时强制 。任何其他计算必须保持两倍。

将一个操作数乘以1.0(即将其转换为加倍)将有助于一点点。所以你可以这样做:

return val * 1.0 / hD * xD;

返回未发布的未结算双。