Simulate the gravitational pull of a star?

隐身守侯 提交于 2019-12-10 14:57:51

问题


I'm making a game where the player will (on release of mouseclick) shoot a "star" in a certain direction at an initial speed determined by how far he dragged the mouse before releasing. I have a "planet" (stationary circle) on the canvas that I want to exert a gravitational pull on the moving planet. I believe I'm using the right formulas for gravitational force and such, and I have it partially working - the planet affects the planet's trajectory up until a certain point, when the star seems to endlessly speed up and stop changing direction based on it's angle to the star. Any advice? (I know that stars aren't supposed to orbit planets, it's the other way around. I coded the whole thing with the names interchanged so forgive that).

main class:

    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;
    }
    }

Pertinent parts of shootingStar class:

     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;

      }
    }

EDIT:

Current Main Class Method:

    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);

    }

Current Star class Method:

    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;

      }
    }

回答1:


Wow, that's a lot more effort than what you "HAVE" to do.

If the thing is on the board calculate it's distance from the object. If it's farther away than D do nothing. If it's D away then it's within the objects gravitational pull. Just add a small amount of velocity to it pointing at the object. Let's say it was 1000 X away and 500 z away. Just do something simple like divide by 100, and add that to the objects velocity so it moves 10 x and 5 y towards the object. Each time you update add the velocity again.

You'll probably want a maximum velocity also. This is a LOT easier to calculate works well, and will give you effects like in the game STAR CONTROL where there's a planet, or the ships gravitationally pull towards each other a tiny bit. I did this with 10 planets and a star, and the user could basically do lunar lander with each planet. It was a blast but I never turned it into a real game. This has the advantage of being rockingly fast to calculate. There some edge conditions like if you make the map a torus so they warp through the sides of the map, but basically it's all just simple addition and subtraction.

It's GOOD enough for a game. You're not making a simulator. You're making a game.




回答2:


I am not sure, but try to change the part where you calculate the xAccel and yAccel values to something like this.

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;

I think your whole yadayada with sine and cosine creates a whole bunch of hard-to-trackdown-errors.



来源:https://stackoverflow.com/questions/13306596/simulate-the-gravitational-pull-of-a-star

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!