Problems with gravity simulation



ArrayList<Body> objects = new ArrayList<Body>(100);
ArrayList<Body> destroy = new ArrayList<Body>();


float m1 = 0.5;
float m2 = 1;
float G = 0.00002;
int maxDist = 1;
float scale = 1;
PVector mouse = new PVector(0, 0);
PVector midPos;
PVector startPos;
boolean hasBeenDragged;
boolean paused;
boolean wasCreated;
boolean C_pressed;
PVector ObjectDir = new PVector(0, 0);
ArrayList<PVector> points = new ArrayList<PVector>();
ArrayList<Body> Copy;

void setup() {
  size(1000, 1000);
  midPos = new PVector(0, 0);
  startPos = new PVector(width / 2, height / 2);
  //fullScreen();

  /*for (int i = 0; i < 10; i++) {
   objects.add(new Body(new PVector(random(-width / 2, width / 2), random(-height / 2, height / 2)), random(50, 80)));
   objects.get(i).applyForce(PVector.random2D().setMag(random(10)));
   }
   for (int i = 0; i < 10; i++) {
   objects.add(new Body(new PVector(random(-width / 2, width / 2), random(-height / 2, height / 2)), random(10)));
   objects.get(i).applyForce(PVector.random2D().setMag(random(0.8)));
   }*/

  frameRate(80);
}

void draw() {
  background(0);
  stroke(255, 50);
  
  points = new ArrayList<PVector>();
  Copy = CopyArray(objects);

  if (keyPressed && key == 'c') {
    strokeWeight(7);
    line(ObjectDir.x, ObjectDir.y, mouseX, mouseY);
    
    /*PVector ObjectDirCopy = ObjectDir.copy();

    ObjectDirCopy = ObjectDirCopy.sub(mouseX, mouseY);
    ObjectDirCopy = ObjectDirCopy.div(80 * scale);
    Copy.add(new Body(new PVector((mouseX - width / 2) / scale - midPos.x, (mouseY - height / 2) / scale - midPos.y), m2));
    Copy.get(Copy.size() - 1).applyForce(ObjectDirCopy);
    Copy.get(Copy.size() - 1).createPreview = true;

    for (int i = 0; i < 1; i++) {
      for (Body b : Copy) {
        b.update();                                                This update() is updating the original body in objects array
        if (b.createPreview) {
          points.add(new PVector(b.pos.x, b.pos.y));
        }
      }
    }*/
  }

  translate(width / 2, height / 2);
  scale(scale);


  translate(mouse.x + midPos.x, mouse.y + midPos.y);
  destroy = new ArrayList<Body>();




  for (PVector p : points) {
    strokeWeight(1 / scale);
    stroke(255);
    point(p.x, p.y);
    //println(p);
  }
  
  for (Body b : objects) {
    b.show();
  }


  if (!paused) {
    for (Body b : objects) {
      b.update();
    }
  }
  if (!paused) {
    for (Body b1 : objects) {
      for (Body b2 : objects) {
        if (b1 != b2) {

          float r = dist(b1.pos.x, b1.pos.y, b2.pos.x, b2.pos.y);
          if (r < (b1.radius + b2.radius)) {
            destroy.add(b1);
            destroy.add(b2);
          }

          PVector p1 = new PVector(b2.pos.x, b2.pos.y);
          PVector p2 = new PVector(b1.pos.x, b1.pos.y);

          p1 = p1.sub(b1.pos);
          p2 = p2.sub(b2.pos);

          float a = G * ((b1.m * b2.m) / (r * r));

          b1.applyForce(p1.mult(a).mult(1));
          b2.applyForce(p2.mult(a).mult(1));

          //stroke(map(r, 0, 500, 255, 0));
          stroke(255, 50);

          //line(b1.pos.x, b1.pos.y, b2.pos.x, b2.pos.y);
        }
      }
    }
  }

  for (Body b1 : destroy) {
    for (Body b2 : destroy) {
      float dist = dist(b1.pos.x, b1.pos.y, b2.pos.x, b2.pos.y);
      if (dist < b1.radius + b2.radius && dist > 0) {
        if (b1.m >= b2.m) {

          objects.remove(b2);
          b1.m += b2.m;
          b1.vel = b1.vel.mult(0.8);
        } else {

          objects.remove(b1);
          b2.m += b1.m;
          b2.vel = b2.vel.mult(0.8);
        }
      }
    }
  }
}


void mousePressed() {
  startPos = new PVector(mouseX, mouseY);
}

void mouseWheel(MouseEvent e) {
  float mv = e.getCount();
  if (scale > 0.5) {
    if (mv < 0) {
      scale -= scale / 2;
    }
  }
  if (mv > 0) {
    scale += scale / 2;
  }
}

void mouseDragged() {
  if (mouseButton == LEFT) {
    mouse = new PVector((mouseX - startPos.x) / scale, (mouseY - startPos.y) / scale);
    hasBeenDragged = true;
  }
}

void mouseReleased() {
  midPos = midPos.add(mouse.copy());
  mouse = new PVector(0, 0);
  if (mouseButton == LEFT && !hasBeenDragged) {
    objects.add(new Body(new PVector((mouseX - width / 2) / scale - midPos.x, (mouseY - height / 2) / scale - midPos.y), m1));
  } else if (!hasBeenDragged) {
    objects.add(new Body(new PVector((mouseX - width / 2) / scale - midPos.x, (mouseY - height / 2) / scale - midPos.y), m2));
  }
  hasBeenDragged = false;
}

void keyPressed() {
  if (key == 'd') {
    objects = new ArrayList<Body>();
  } else if (key == 'p') {
    paused = paused? false : true;
  } else if (key == 'c' && !C_pressed) {
    C_pressed = true;
    ObjectDir = new PVector(mouseX, mouseY);
  }
}


void mouseMoved() {
}


void keyReleased() {

  if (C_pressed) {
    if (key == 'c' && !wasCreated) {
      wasCreated = true;
      ObjectDir = ObjectDir.sub(mouseX, mouseY);
      ObjectDir = ObjectDir.div(80 * scale);
      objects.add(new Body(new PVector((mouseX - width / 2) / scale - midPos.x, (mouseY - height / 2) / scale - midPos.y), m2));
      objects.get(objects.size() - 1).applyForce(ObjectDir);
    }
    
    for(Body b : objects){
      b.createPreview = false;
    }
  }


  wasCreated = false;
  C_pressed = false;
}





ArrayList<Body> DoGravity(ArrayList<Body> b_in) {
  ArrayList<Body> result = new ArrayList<Body>();

  for (Body b1 : b_in) {
    for (Body b2 : b_in) {
      if (b1 != b2) {

        float r = dist(b1.pos.x, b1.pos.y, b2.pos.x, b2.pos.y);
        if (r < (b1.radius + b2.radius)) {
          destroy.add(b1);
          destroy.add(b2);
        }

        PVector p1 = new PVector(b2.pos.x, b2.pos.y);
        PVector p2 = new PVector(b1.pos.x, b1.pos.y);

        p1 = p1.sub(b1.pos);
        p2 = p2.sub(b2.pos);

        float a = G * ((b1.m * b2.m) / (r * r));

        b1.applyForce(p1.mult(a).mult(1));
        b2.applyForce(p2.mult(a).mult(1));
      }
    }
  }
  result = b_in;
  return result;
}


ArrayList<Body> CopyArray(ArrayList<Body> b){
  ArrayList<Body> result = new ArrayList<Body>();
  
  for(Body b1 : b){
    Body o = b1.copy();
    result.add(o);
  }
  
  return result;
} 
class Body {
  PVector pos;
  PVector vel = new PVector(0, 0);
  PVector acc = new PVector(0, 0);
  float m;
  float radius = 0;
  boolean createPreview;

  Body(PVector pos_, float m_) {
    pos = pos_;
    m = m_;
  }

  void update() {

    vel = vel.add(acc.div(m));
    vel.limit(5);
    acc = new PVector(0, 0);
    pos = pos.add(vel);


    vel.mult(1);


    if (m > 300) {
      m -= map(m, 0, 300, 0, 0.1);
    }
  }

  void applyForce(PVector acc_) {
    acc.add(acc_);
  }

  void show() {
    radius = min(m / 20, 30);
    stroke(255);
    noFill();
    strokeWeight(radius * 2);
    point(pos.x, pos.y);
    //line(pos.x, pos.y, vel.x * 20 + pos.x, vel.y * 20 + pos.y);
  }


  Body copy() {
    Body b = new Body(this.pos, this.m);
    b.vel = this.vel;
    b.acc = this.acc;
    return b;
  }
}
1 Like

I marked the spot in the code, that creates the problem. There is an update() which not only updates the bodys in the copy, but also the original.

Please consider breaking this code down to a minimal reproducable example and explaining what exactly the problem is. That way we will be much more likely to be able to help you out. :wink:

1 Like

Im trying to create a preview of a path a body will take if created with a specific velocity and position.
So im trying to copy an array of these bodys to do the simulation. but if i do update() on the body in the copied array it updates the one in the original array. If you run the code and uncomment the part at the top, when pressing c the other bodys will speed up

Your copy method doesn’t do what you want it to do. It creates a new instance of Body, which is good, but it doesn’t copy the fields of the original body, meaning you just pass reference to the same objects.

To fix this, change your Body#copy method to:

Body copy() {
  Body b = new Body(this.pos.copy(), this.m);
  b.vel = this.vel.copy();
  b.acc = this.acc.copy();
  return b;
}
2 Likes