模拟恒星的引力?

Posted

技术标签:

【中文标题】模拟恒星的引力?【英文标题】:Simulate the gravitational pull of a star? 【发布时间】:2012-10-29 16:27:27 【问题描述】:

我正在制作一个游戏,玩家将(释放鼠标)以初始速度朝某个方向射出一颗“星星”,该初始速度取决于他在释放之前拖动鼠标的距离。我在画布上有一个“行星”(固定圆),我想对移动的行星施加引力。我相信我正在使用正确的引力等公式,并且我让它部分工作 - 行星影响行星的轨迹直到某个点,当恒星似乎无休止地加速并停止根据它的角度改变方向到星星。 有什么建议? (我知道恒星不应该围绕行星运行,它是相反的。我用互换的名字编码了整个事情,所以请原谅)。

主类:

    import acm.graphics.GCompound;
    import acm.graphics.GImage;
    import acm.graphics.GLabel;
    import acm.graphics.GLine;
    import acm.graphics.GMath;
    import acm.graphics.GObject;
    import acm.graphics.GPen;
    import acm.graphics.GPoint;
    import acm.graphics.GRect;
    import acm.graphics.GOval;
    import acm.graphics.GRectangle;
    import acm.program.GraphicsProgram;
    import acm.util.RandomGenerator;
    import java.awt.Color;
    import java.awt.event.MouseEvent;
    import java.util.*;

    public class Space extends GraphicsProgram 
      public static int APPLICATION_WIDTH = 1000;
      public static int APPLICATION_HEIGHT = 1000;
      private int size = 15;
      public static double pMass = 1000;
      public static int sMass = 20;
      public static double G = 200;
      private RandomGenerator rand = new RandomGenerator();
      GOval planet, tempstar;
      shootingStar star;
      GLine line;
      double accel, xAccel, yAccel, xspeed, yspeed, angle;


      public void init()
        planet = new GOval(APPLICATION_WIDTH/2, APPLICATION_HEIGHT/2, 30, 30);
        planet.setFilled(true);
        planet.setFillColor(rand.nextColor());
        add(planet);

      


      public void mousePressed(GPoint point) 
        // draw a line
        tempstar = new GOval(point.getX() - size/2, point.getY() - size/2, size, size);
        tempstar.setFilled(true);
        tempstar.setColor(rand.nextColor());
        add(tempstar);
        line = new GLine(tempstar.getX() + size/2, tempstar.getY() + size/2, 
    point.getX(), point.getY());                             
        add(line);
        line.setVisible(true);
      

      public void mouseDragged(GPoint point) 
        line.setEndPoint(point.getX(), point.getY());
      

      public void mouseReleased(GPoint point)
        xspeed =            
    -.05*GMath.cosDegrees(getAngle(line))*GMath.distance(line.getStartPoint().getX(),         
    line.getStartPoint().getY(), line.getEndPoint().getX(), line.getEndPoint().getY());
        yspeed = 
    .05*GMath.sinDegrees(getAngle(line))*GMath.distance(line.getStartPoint().getX(), 
    line.getStartPoint().getY(), line.getEndPoint().getX(), line.getEndPoint().getY());
        System.out.println(xspeed + " " + yspeed);
        star = new shootingStar(xspeed, yspeed, this);
        if(xspeed != 0)
          add(star, tempstar.getX(), tempstar.getY());
        new Thread(star).start();
        remove(tempstar);
        remove(line);

      

      private double getAngle(GLine line) 
        return GMath.angle(line.getStartPoint().getX(), line.getStartPoint().getY(), 
                           line.getEndPoint().getX(), line.getEndPoint().getY());
      


      public void checkPlanet()
        accel = .06*GMath.distance(star.getX(), star.getY(), planet.getX(), 
    planet.getY());
        angle = correctedAngle(GMath.angle(planet.getX(), planet.getY(), star.getX(), 
    star.getY()));       
        xAccel = accel*GMath.cosDegrees(GMath.angle(planet.getX(), planet.getY(), 
    star.getX(), star.getY()));
        yAccel = accel*GMath.sinDegrees(GMath.angle(planet.getX(), planet.getY(), 
    star.getX(), star.getY()));

        double newX = xspeed - xAccel*.01;
        double newY = yspeed + yAccel*.01;

        xspeed = newX + xAccel*Math.pow(.01, 2)/2;
        yspeed = newY + yAccel*Math.pow(.01, 2)/2;

        star.setSpeed(xspeed, yspeed);


      

      public double correctedAngle(double x) 
        return (x%360.0+360.0+180.0)%360.0-180.0;
    
    

shootingStar类的相关部分:

     public void run() 
        // move the ball by a small interval
        while (alive) 
        oneTimeStep();
        
      

      // a helper method, move the ball in each time step
      private void oneTimeStep() 
        game1.checkPlanet();
        shootingStar.move(xSpeed, ySpeed);
        pause(20); 
      

      public void setSpeed (double xspeed, double yspeed)
        xSpeed = xspeed;;
        ySpeed = yspeed;

      
    

编辑:

当前主类方法:

    public void checkPlanet()
        double xDistance = star.getX() - planet.getX();
        double yDistance = star.getY() - planet.getY();
        double distance = Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
        accel = G*pMass/Math.pow(distance, 2);

        xAccel = accel * xDistance/distance;
        yAccel = accel * yDistance/distance;

          xspeed += xAccel;

         yspeed += yAccel;

       star.setSpeed(xspeed, yspeed);

    

当前星类方法:

    public void run() 
        while (alive) 
          oneTimeStep();
        
      

      private void oneTimeStep() 
        game1.checkPlanet();
        shootingStar.move(xSpeed, ySpeed);
        pause(20); 
      

      public void setSpeed (double xspeed, double yspeed)
        xSpeed = xspeed;;
        ySpeed = yspeed;

      
    

【问题讨论】:

在阅读了一整天的 TDWTF 之后,最终停在了 this,我暂时觉得有必要问一下您是想模拟万有引力还是只是模拟它背后的数学。 【参考方案1】:

哇,这比你“必须”做的要多得多。

如果物体在板上,请计算它与物体的距离。如果它比 D 远,什么也不做。如果它在 D 之外,那么它在物体的引力范围内。只需将少量速度添加到它指向对象。假设它在 1000 X 和 500 z 之外。只需做一些简单的事情,例如除以 100,然后将其添加到对象速度上,使其向对象移动 10 x 和 5 y。每次更新时再次添加速度。

您可能还需要最大速度。这很容易计算,效果很好,并且会给你带来类似游戏 STAR CONTROL 中的效果,其中有一颗行星,或者船只在引力的作用下相互拉近一点点。我用 10 颗行星和一颗恒星来做这个,用户基本上可以用每个行星做月球着陆器。这是一个爆炸,但我从来没有把它变成一个真正的游戏。这具有计算速度非常快的优势。有一些边缘条件,比如如果你把地图做成一个圆环,那么它们会在地图的两侧弯曲,但基本上这只是简单的加法和减法。

对于游戏来说已经足够了。你不是在制作模拟器。你正在制作游戏。

【讨论】:

【参考方案2】:

我不确定,但请尝试将计算 xAccel 和 yAccel 值的部分更改为类似的值。

xDistance = XComponentObject1 - XComponentObject2; 

yDistance = YComponentObject1 - YComponentObject2;

(xDistance and yDistance can have negative values)

Distance = sqrt( xDistance^2 + yDistance^2 );

gConstant = constant Value for gravitational strenght in your world;

MassObject1 = some Mass;

MassObject2 = some other Mass;

Accel = gConstant*MassObject1*MassObject2 / (Distance^2 );

''NOW COMES THE IMPORTANT PART''

xAccel = Accel * xDistance/Distance;

yAccel = Accel * yDistance/Distance;

我认为你的正弦和余弦的整个 yadayada 会产生一大堆难以追踪的错误。

【讨论】:

谢谢 - 这绝对比我之前的工作更有效。不过,同样的问题似乎仍然存在——我如何解释这样一个事实,即当恒星被吸入行星的引力场时,它应该(并且确实)加速。当它被“推出”另一边时(假设它没有与地球相撞),它应该减速。我的星星的速度不断增加。 这对我来说听起来像是一个符号错误。之后,您对 Accelerateen 值究竟做了什么?我不明白你的代码的意义。试试看:'NewXspeed = OldXspeed + xAcceltimefactor; ' NewYspeed = OldYspeed + yAcceltimefactor; ' 用当前代码更新了问题 - 仍然有两个问题:引力场在相反的方向工作 - 所有物体都被推离中心行星,2) 恒星不做完整的轨道——它更像是一个部分轨道,它们会变得越来越快,直到它们沿着一条直线前进。有什么建议吗?非常感谢! 关于您的第一个问题:只需为您的引力常数使用负值。

以上是关于模拟恒星的引力?的主要内容,如果未能解决你的问题,请参考以下文章

利用threejs基于万有引力公式模拟宇宙三体

1台笔记本模拟黑洞引力波,和超算2个月得出的结果只差1%

1台笔记本模拟黑洞引力波,和超算2个月得出的结果只差1%

html “Flot:jQuery的有吸引力的JavaScript绘图。”与IE8兼容,但IE8需要模拟HTML5画布(使用ExCanvas)。德

四种作用力中最弱的引力,为何能坍缩出宇宙无敌的黑洞?

如何从一系列照片中计算出恒星旋转?