无法在我的太阳系模型上获得正确的轨道
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),而且加速度的方向比应该导致轨道旋转晚一步(因为加速度是从不同的位置计算的)而不是应用于最终位置,因此它的方向始终是关闭的)。
我只使用 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),而且加速度的方向比应该导致轨道旋转晚一步(因为加速度是从不同的位置计算的)而不是应用于最终位置,因此它的方向始终是关闭的)。