无法在我的太阳系模型上获得正确的轨道

Unable to get a proper orbit on my solar system model

我只使用 p5.js 并且没有使用 box2D 制作太阳系模型,尽管语言/平台对于这个问题无关紧要。此外,用于描述问题的所有数字和变量并非 100% 准确,但行为是相同的。

我使用牛顿公式 ( F = G Mm / r^2 ) 求出两个物体(例如 A 和 B)之间的相互引力。现在为了将 A 吸引到 B,我将这种相互引力除以 A 的质量为找到 A 上的向心加速度,然后将其乘以指向 B 的单位向量。将此关系应用于 A 和 B 时,它们都会相互吸引,与它们的质量成反比。

现在,如果我让它们彼此相互作用,A 的质量 = 1000 个单位,B 的质量 = 10 个单位,正如预期的那样,A 不会被拉动并保持静止,但 B 会加速朝向 A。现在发生的事情是当 B 到达中心并朝相反的方向飞行时,它比我最初放置它的距离更远。在每个加速周期中,这会继续滚雪球,并在某个时候消失在屏幕上。这似乎违反了能量守恒或我的物理学中的一些重大缺陷。

好吧,那么继续第二个问题,我们有相同的物体和质量。不同之处在于,我给 B(较轻的物体)一个某个值的初始速度,比如在 x 轴的正方向上的 x。现在我将 B 垂直于 A 的 x 轴并让它们相互作用。这一次,B 在椭圆轨道上移动,有两个问题。首先是 A(较重的物体)不在椭圆的焦点之一,而是恰好位于椭圆的中心,其次是随着时间的推移,轨道本身开始旋转。我觉得这种旋转是由提供的初始速度引起的,只是为了清楚起见,速度最初只应用,而不是应用于每一帧。该轨道轨迹如下:

还要注意每个轨道的最大范围比前一个大一点。这几乎是以前的问题。

我目前正在尝试的下一件事是,应用恒定的切向运动速度以及重力向心加速度。让我知道这是否有用,或者我的整个方法是否需要更改。

这也是我的模拟代码:

var constG;
var axisX;
var planets = [];

function setup() {
  createCanvas(500, 500);
  //createCanvas(displayWidth, displayHeight);
  //fullscreen(true);
  constG = 0.0001;//6.67 * pow(10, -11);
  axisX = createVector(1, 0);
}

function draw() {
  background(0, 5);
  for (var planet of planets) {   
    planet.update();
    planet.display();
  }

  for (var i = 0; i < planets.length; i++){
    var selfPlanet = planets[i];
    for (var j = 0; j < planets.length; j++){
      if (j == i){
        continue;
      }
      var otherPlanet = planets[j];
      var gravitalAcc = calcGravitalAcc(selfPlanet, otherPlanet);
      selfPlanet.applyForce(gravitalAcc);
    }
  }
  
  if (planets.length > 0){
    planets[0].radius = 15;
    planets[0].mass = 100;    // this just makes the first planet heavy so that i 
    planets[0].vel.mult(0);   // can test stuff while making it the sun.
    planets[0].speed = 0;
  }
}

function mousePressed() {
    planets.push(new CelestialBody(mouseX, mouseY, 7));
}

function calcGravitalAcc(self, other){
  var tempVec = p5.Vector.sub(other.pos, self.pos);
  return tempVec.normalize().mult(constG * (other.mass)/pow(tempVec.mag(), 2))
}

这是天体 class,只是简单物理模拟中的任何典型 class:

class CelestialBody {
  constructor(x, y, radius) {
    this.pos = createVector(x, y);
    this.radius = radius;
    this.color = color(255);
    
    this.mass = 1;
    this.speed = 1;
    this.vel = createVector(1, 0) //p5.Vector.random2D();
    this.vel.setMag(this.speed);
    this.acc = createVector(0, 0);
  }

  display() {
    fill(this.color);
    stroke(this.color);
    circle(this.pos.x, this.pos.y, this.radius * 2);
  }

  update() {
    this.pos.add(this.vel);
    this.vel.add(this.acc);
    this.acc.mult(0);
  }
  
  applyForce(vForce){
    this.acc.add(vForce);
  }
}

第一个问题通常是由于模拟的时间步长过大而没有碰撞处理。当你的物体靠近时,力变大,模拟中的增量步长变得太大,所以下一个迭代位置是在碰撞之后,通常比碰撞之前更远,所以破断力更小,导致时间轨道越来越大。 .

要解决这个问题,您可以这样做:

  • 添加碰撞处理
  • 将最大速度或力量限制在某个理智的极限

我从来没有遇到过你的第二个问题而且没有代码我什至猜不出来...除了舍入错误

看看这个:

还有所有子链接...

[Edit1] 在我看到你的代码后

代码的体系结构看起来不错,问题是您的方程式略有偏差。应该是:

vel+=acc*dt;
pos+=vel*dt;
acc=0.0;

而不是你的:

pos+=vel;
vel+=acc;
acc=0.0;

所以你得到了错误的顺序并且错过了 *dt 其中 dt 是时间步长。因此,无论您如何更改计时器间隔,结果都是相同的(只是 slower/faster),而且加速度的方向比应该导致轨道旋转晚一步(因为加速度是从不同的位置计算的)而不是应用于最终位置,因此它的方向始终是关闭的)。