【创意编程】《无限》:宇宙、三体、星云和轨迹

【创意编程】《无限》:宇宙、三体、星云和蚕丝

————————————————————————————————
————————————————————————————————
一颗恒星。不知道有多少不起眼的小行星日日夜夜绕着它,有些却飞向无限的远点。宇宙有限吗?它们还会回来吗?
在这里插入图片描述
一个没有调好的三体模型
在这里插入图片描述
不知道什么给我的灵感,也不知道从哪来的想法,想着既然要做一个力,不如做大点,做个大的,甚至做个完整的系统。一开始其实没有很多想法,只想做一个三体的运动,但是本来三体就不稳定,而且我调了一下午的参数也没有调出一个相对稳定的且包含几种基本的天体状态的参数来。而且简单的三体运动在实现技术上也其实没有什么很大的困难,而且三个球孤零零的,也不是很好看。于是就想不如先做一个恒星系,然后去描绘他们的运动,或许可以有一些有意思的图案出现。于是就去做了,而且意外地发现效果真的还不错,是我想要的那种感觉。
由于我想要模拟看起来很舒服的天体系统,所以天体的运动都不会很快,在这里放全过程的gif是不现实的,就只能截图示意一下效果。
我们将在宇宙中随机分布一些具有随机初速度、随机位置、随机质量(小质量)的小行星。考虑到计算性能和,并且我们还需要画轨迹,我们的小行星数目不应该太多。上面的动图由于在台式机上跑性能较好,给了50个行星。如果是笔记本上,20个就已经够了。
恒星的质量和行星不在一个数量级。在这个系统里,我为了显示的效果,定义了恒星的质量为1000,行星则为1到3。
在这里插入图片描述
所有的星球被加入后构成星球列表。对于画布上的每一个星球,我们都需要计算其他所有星球对它施加的万有引力。在这个系统中,恒星只有一颗且远远重于行星,周围其他行星的万有引力就显得微乎其微。
受到万有引力作用,行星开始改变运动轨迹以及速度。
在这里插入图片描述
一些初速度大的直接逃逸了。虽然它终究还是会被拉回来,但是这已经不重要了。
另一些的运动轨迹则非常直观地刻画了高中物理课上的天体物理模型。
在这之后,轨迹变得复杂,画面中的轨迹线也变多。
这个图不好看。我们重新运行一下看看。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
最终构成了非常美妙的样子。
在这里插入图片描述
运动轨迹真的好妙呀。

————————————————

万有引力仿真

根据万有引力公式,F = G * (m1 * m2)/ r^2。
我们就根据这个公式把力写出来。
与前面的作业不同,这里的速度因为涉及到旋转、椭圆计算,我们需要的是PVector类型的速度以及加速度,力也是有方向的。这个力是所有星球给予这个星球的力的矢量叠加,故也需要用PVector类型来表示。

  public void calculateForce(ArrayList<Planet> planets, int currentIndex){
    for (int i = 0; i< planets.size(); i++){
      if (i != currentIndex){
        Planet p = planets.get(i);
        PVector offset = new PVector((p.position.x - position.x), (p.position.y - position.y));
        float distance = sqrt(sq(offset.x) + sq(offset.y));
        float thisforce = mass * p.mass / sq(distance);//no direction 
        PVector forceNorm = offset.normalize();
        PVector thisForce = forceNorm.mult(thisforce);
        force = PVector.add(force, thisForce);
      }
    }
  }

其中,我们需要施加每一个来自自己以外所有星球的引力,就需要在调用方法的时候传入所有星球的数组,并对自己以外的任何星球进行同等的处理,才能够得到准确的合力。当然,在我们这个认为恒星是中心的系统中,恒星不需要进行这样的处理。

应用万有引力

  public void applyForce(){
      acceleration = force.div(mass);
      velocity.add(acceleration);
      position.add(velocity);
      acceleration = new PVector(0, 0);
      force = new PVector(0,0);
  }

————————————

绘制轨迹

和上一章使用的方法一样,在上面蒙一层透明画布,不擦除轨迹,用于记录并且显示轨迹。

PGraphics route;
route = createGraphics(width, height);

void draw(){
  //background(0);
  image(route, 0, 0);
  fill(255,0,0);
  noStroke();
  ellipse(solar.position.x, solar.position.y, 20,20);
  for (int i = 1; i < planets.size(); i++){
      Planet p = planets.get(i);
      p.calculateForce(planets, i);
      p.applyForce();
      p.display();
      route.beginDraw();
      route.strokeWeight(0.1);
      route.stroke(255);
      route.point(p.position.x, p.position.y);
      route.endDraw();
  }
}

我很喜欢这个代码,也很喜欢这个想法。或许我还可以把它做成一个完整的可以人手动创造的系统。

——————————————————————————

完整代码

主类:

ArrayList<Planet> planets;
PGraphics route;
Planet solar;
int planetNum = 50;

void setup(){
  size(1600,1000);
  background(0);
  route = createGraphics(width, height);
  planets = new ArrayList<Planet>();
  solar = new Planet(1000, width/2,height/2, 0, 0);
  planets.add(solar);
  noStroke();
  //fill(255,0,255);
  //m, x, y;
  for (int i = 0; i< planetNum; i++){
    Planet p = new Planet(random(1,3), random(width), random(height), random(-2, 2), random(-2, 2));
    planets.add(p);
  }
}

void draw(){
  //background(0);
  image(route, 0, 0);
  fill(255,0,0);
  noStroke();
  ellipse(solar.position.x, solar.position.y, 20,20);
  for (int i = 1; i < planets.size(); i++){
      Planet p = planets.get(i);
      p.calculateForce(planets, i);
      p.applyForce();
      p.display();
      route.beginDraw();
      route.strokeWeight(0.1);
      route.stroke(255);
      route.point(p.position.x, p.position.y);
      route.endDraw();
  }
}

行星的Planet类:

class Planet{
  float mass;
  PVector position;
  PVector velocity;
  PVector acceleration;
  PVector force;
  
  Planet(float m, float x, float y, float vx, float vy){
    mass = m;
    position = new PVector(x, y);
    velocity = new PVector(vx, vy);
    acceleration = new PVector(0, 0);
    force = new PVector(0, 0);
  }
  
  public void calculateForce(ArrayList<Planet> planets, int currentIndex){
    for (int i = 0; i< planets.size(); i++){
      if (i != currentIndex){
        Planet p = planets.get(i);
        PVector offset = new PVector((p.position.x - position.x), (p.position.y - position.y));
        float distance = sqrt(sq(offset.x) + sq(offset.y));
        float thisforce = mass * p.mass / sq(distance);//no direction 
        PVector forceNorm = offset.normalize();
        PVector thisForce = forceNorm.mult(thisforce);
        force = PVector.add(force, thisForce);
      }
    }
  }
  
  public void applyForce(){
      acceleration = force.div(mass);
      velocity.add(acceleration);
      position.add(velocity);
      acceleration = new PVector(0, 0);
      force = new PVector(0,0);
  }
  
  public void display(){
      fill(255, 255, 255);
      ellipse(position.x, position.y, 1, 1);
      stroke(255);
      strokeWeight(1);
  }
}

三体

在我已经写好的系统中,对恒星、行星进行了同样的处理,所以要想模拟单体模型,只需要加进去两个恒星,把行星舍去。
三体本身就是一个非常不稳定的状态,我调了一天的参数还是没能找到相对稳定的状态。但它真的不难。
不多赘述了。

EasyX是一个轻量级的C++游戏开发框架,它简化了游戏图形编程,特别是2D图形的处理。如果你想用EasyX做三体运动(通常指的是模拟经典物理中的三体问题),你可以按照以下步骤进行: 1. **安装和设置EasyX**: 首先,确保你已经下载并包含了EasyX库到你的C++项目中。如果你还没有安装,可以从其官网下载源码或者集成开发环境(IDE)插件。 2. **创建场景和物体**: 创建一个窗口,并使用EasyX的`Scene`类来管理你的场景。为每个三体创建一个或多个`Object`对象,它们将代表星体。 3. **定义三体模型**: 设定每个星体的质量、位置和速度。三体问题通常涉及到三个星体,可以设定两个作为大质量的恒星(比如太阳),第三个作为小质量的行星或彗星。 4. **计算运动**: 使用牛顿运动定律,特别是万有引力定律,来计算星体之间的相互作用力。EasyX可能没有内置的物理引擎,但你可以手动实现这些计算。 5. **更新和绘制**: 在每一帧游戏中,根据上一帧的运动状态,更新星体的位置和速度。然后调用`Scene`的`draw()`方法来渲染它们。 6. **动画循环**: 使用游戏循环,不断重复上述步骤(更新、计算和绘制),使星体看起来在运动。 相关问题-- 1. EasyX如何处理游戏对象的移动和位置更新? 2. 如何在EasyX中模拟星体间的引力相互作用? 3. 如何在EasyX中实现一个基本的动画循环来显示三体运动?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值