Ognjen
Ognjen

Reputation: 11

Need help figuring out orbits in 2D for my game

In a game that I'm making, the idea is that the mouse cursor is representing a center of mass and there are objects orbiting around it. The cursor itself is not an object and there is no collision between the cursor and the objects.

The ideal method would be the one where I can enter x and y coordinates of the target, and maybe the orbit radius, and the object would go into orbit and would be accelerating constantly.
When I move the mouse, the object would follow; and when I stop it, it would fall back into the same orbit radius.
The objects acceleration should also be able to change so it gives an effect that the mouse has more or less mass.

I thought the best way to achieve this would probably be with vectors.

In the Projectile class I gave each projectile 4 fields: x coordinate, y coordinate, PVector speed and PVector acc (acceleration).

The first thing I tried is giving the object constant acceleration. Speed vector starts as zero, the acceleration vector is calculated, its magnitude is then set to some value and it is added to the speed vector. This produced very large orbits, slow acceleration and when the mouse is moved, the orbit just became larger.

Next I tried making the acceleration increase when it is closer to the center of mass inspired by the actual planets. This did not work either. The orbits were still too large and not controllable. Kind o disappointed I tried making the acceleration constantly increasing which gave the best results. The orbit is now getting smaller, but it just keeps decreasing to some radius and then stops. This would be perfect if the radius at which it stops decreasing would be configurable, but no matter the parameters the orbit is always too large and the orbit size keeps decreasing frustratingly slowly. My guess is that the acceleration and speed somehow end up in an equilibrium, and then the orbit stops decreasing.

void move(float x,float y,float accm)
  {
    PVector target = new PVector(x, y);
    PVector ball = new PVector(this.x, this.y);
    acc = PVector.sub(target, ball);
    acc.setMag(accm);
    speed.add(acc);
    println(acc.mag() + " " + speed.mag());
    this.x = this.x + speed.x;
    this.y = this.y + speed.y;
  }

This is the function that gave the best results. The function is called in draw():

if(mousePressed == true)
  {
    for(i=0;i<nproj;i++)
    {
      a[i].move(mouseX, mouseY,k);
    }
    k += n;
  }

k is the number given to the function and n is the rate at which acceleration increases. I tried many different acceleration magnitudes and different rates of acceleration and just couldn't figure it out. Nproj is the number of projectiles and a is the name of the projectile array.

I found that for k = 0 and n = 0.002 it gave the most reliable and stable results. If n is larger (around 0.01 or larger), the objects sometimes randomly flies off way further than expected, and it actually increases the orbit radius. As the acceleration increases this happens more often, and the object sometimes ends up off the screen and then it never comes back. I know that orbit radius doesn't exist because the orbits are elliptical, but it just makes it easier to explain.

Update: This is what I came up with so far

void move(float x,float y,float accm)
  {
    PVector target = new PVector(x, y);
    PVector ball = new PVector(this.x, this.y);
    acc = PVector.sub(target, ball);
    acc.setMag(accm);
    vel.add(acc);
    this.x = this.x + vel.x;
    this.y = this.y + vel.y;
    vel.limit(15);
  }

and in draw()

if(mousePressed == true)
  {
    for(i=0;i<nproj;i++)
    {
      a[i].move(mouseX, mouseY,k);
    }
    k += n;
    if(k > 25)
    n = 0;
  }

By limiting the velocity vector and constantly increasing acceleration vector, magnitude difference begins to increase and since the acceleration vector is increasing and the velocity vector is constant and acceleration vector points towards the target the sum of the vectors starts slowly pointing more and more towards the target. The condition if(k < 25) is there to limit the acceleration and by changing the limit of the acceleration you can change the orbit radius.

Upvotes: 1

Views: 673

Answers (1)

We Are All Monica
We Are All Monica

Reputation: 13336

I think you probably would have gotten a quicker answer over at https://physics.stackexchange.com/ and framing your question as "how do I simulate gravity in a game?"

Anyway I will give it a try...

In the class Projectile I gave each projectile 4 fields: x coordinate, y coordinate PVector speed and PVector acc

Sounds good so far, except you don't need to store the acceleration vector with the object. You'll calculate a new acceleration vector for each object on each "tick" of your simulation.

I would use standard physics terminology here and call each object's vector velocity instead of speed.

Next I tried making the acceleration increase when it is closer to the center of mass inspired by the actual planets.

This behavior should just happen naturally if you use the right algorithm for calculating an orbit.

Your "sun" and the "planets" each have a mass. Masses attract each other with a gravitational force, which is F = G * m1 * m2 / d^2 from Wikipedia.

Remember that Force = mass * acceleration, and you have the acceleration as a = m * G / d^2 where m is the mass of the other object (in this case the sun), and d is the distance between the two objects. So the important part is that the acceleration of an object due to gravity varies with the distance squared between the two objects.

So your basic algorithm for a single tick of your simulation looks like this:

  • For each planet, calculate an acceleration vector
  • Use the distance to the "sun" squared as the magnitude of the acceleration vector (times a constant value that depends on your "gravitational constant" and your sun's mass), and the direction is of course the direction from the planet towards the sun
  • Add this acceleration vector to the velocity vector for the planet
  • Add the velocity vector to the (x, y) position of the planet to move it forward.

With appropriate values for the length of each simulation tick, the gravitational constant, and the sun's mass, this should start to look pretty reasonable.

Since you're assuming that the planets are all independent and cannot collide, you can just do the calculation independently for each planet.

However, I think the game might be more interesting with a more accurate simulation. In reality, every object has a gravitational force on every other object. This would mean looping over all pairs of objects and doing the same kind of acceleration/velocity/position calculation.

The point of the game could then be to get the "planets" from one side of the screen to the other, in increasingly difficult starting configurations as they are all affecting each other and moving in different directions.

In order to make all of this work well, it would be important to set the mass of the "sun" many times higher than the mass of the planets, and to choose a reasonable value for your gravitational constant based on the timing of your simulation. You'll have to play with these constants to find the best results.

Upvotes: 1

Related Questions