• fullscreen
  • Attractor.pde
  • Particle.pde
  • WorldData.pde
  • gravity_attractor.pde
  • class Attractor
    {
      PVector position = new PVector(width/2, height/2);
      float strength = 1;
      
      
      public Attractor() { }
      
      public Attractor(PVector position, float strength)
      {
        this.position = position;
        this.strength = strength;
      }
      
      float getRadius()
      {
        return 2+strength;
      }
      
      
      void draw()
      {
        noStroke();
        fill(0);
        float radius = getRadius();
        ellipse(position.x,position.y,radius, radius);
      }
    }
    
    class Particle
    {
      PVector position = new PVector(width/2,height/2);
      PVector speed = new PVector(0,0);
      PVector maxSpeed = new PVector(14,14);
      float radius = 6;
      WorldData wd;
      
      public Particle(WorldData wd) 
      {
        this.wd = wd;
      }
      
      public Particle(WorldData wd, PVector position)
      {
        this(wd);
        this.position = position;
      }
      
      public Particle(WorldData wd, PVector position, PVector speed)
      {
        this(wd,position);
        this.speed = speed;
      }
      
      
      
      void run(ArrayList attractors)
      {
        update(attractors);
        draw();
      }
      
      void update(ArrayList attractors)
      {
        PVector[] components = new PVector[attractors.size()];
        
        PVector resultant = new PVector(0,0);
        for(int i = 0; i < attractors.size(); i++)
        {
          Attractor a = (Attractor)attractors.get(i);
          float d = dist(a.position.x, a.position.y, position.x, position.y)+1;
          float force = 0;
          if(d < a.getRadius() + radius)
            force = wd.gravitationalConstant*d/a.strength;//(pow(d,2));
          else
            force = wd.gravitationalConstant*a.strength/pow(d,0.9);
          float angle = atan2(a.position.y - position.y, a.position.x - position.x);
          components[i] = new PVector(force*cos(angle), force*sin(angle)); 
          resultant.add(components[i]);
          //resultant = new PVector(resultant.x + force*cos(angle), resultant.y + force*sin(angle));
        }
        speed.add(resultant);
        
        if(speed.x > maxSpeed.x)
          speed.x = maxSpeed.x;
        if(speed.y > maxSpeed.y)
          speed.y = maxSpeed.y;
        
        position.add(speed);
        
        if(position.x < radius)
          speed.x = abs(speed.x);
        else if(position.x > width-radius)
          speed.x = -abs(speed.x);
          
        if(position.y < radius)
          speed.y = abs(speed.y);
        else if(position.y > height-radius)
          speed.y = -abs(speed.y);
        
        if(wd.showAcc)
        {
          stroke(255,50,0);
          line(position.x, position.y, position.x + 100*resultant.x, position.y + 100*resultant.y);
        }
        
        if(wd.showVel)
        {
          stroke(50,0,255);
          line(position.x, position.y, position.x + 10*speed.x, position.y + 10*speed.y);
        }
        
        if(wd.showComps)
        {
          stroke(#D99D00);
          for(int i = 0; i < components.length; i++)
            line(position.x, position.y, position.x + 50*components[i].x, position.y + 50*components[i].y);
        }
      }
      
      void draw()
      {
        noStroke();
        fill(50,255,0);
        ellipse(position.x, position.y,radius,radius);
      }
    }
    
    public class WorldData
    {
      public boolean showAcc = true;
      public boolean showVel = true;
      public boolean showComps = false;
      public float gravitationalConstant = 1;
    }
    
    ArrayList attractors = new ArrayList();
    ArrayList particles = new ArrayList();
    WorldData wd = new WorldData();
    Particle p;
    
    boolean addingAttractor = false;
    PVector initialPos;
    
    boolean showHelp = true;
    PFont calibri25, calibri16, calibri30;
    
    void setup()
    {
      size(900,600,JAVA2D);
      //frameRate(10);
      noLoop();
      smooth();
      noStroke();
      fill(0);
      background(255);
      ellipseMode(RADIUS);
      
      calibri30 = loadFont("Calibri-30.vlw");
      calibri25 = loadFont("Calibri-25.vlw");
      calibri16 = loadFont("Calibri-16.vlw");
      textAlign(LEFT, TOP);
    
      particles.add(new Particle(wd,new PVector(width*2/3, height/2-50), new PVector(0,0)));
      attractors.add(new Attractor(new PVector(width*2/5, height*2/5), 45));
      attractors.add(new Attractor(new PVector(width*4/5, height*3/5), 40));
      //attractors.add(new Attractor(new PVector(width*1/5, height*4/5), 20));
    }
    
    void draw()
    {
      background(255);
    
      if(showHelp)
      {
        fill(0);
        textAlign(LEFT, TOP);
        
        textFont(calibri30);
        textSize(30);
        text("Help",15,15);
        
        textFont(calibri25);
        textSize(25);
        text("Controls",15,55);
        text("Tips",15,395);
        
        textFont(calibri16);
        textSize(16);
        
        text("Left Click - Create a new particle.",15,95);
        text("Right Click - Create a new attractor (click and drag to select the size).",15,115);
        text("Middle Click - Remove an attractor (by middle clicking on it).",15,135);
        
        text("R - Remove all particles.",15,175);
        text("T - Remove all attractors.",15,195);
        
        text("A - Toggle showing the acceleration size + direction. (Red).",15,235);
        text("V - Toggle showing the velocity size + direction. (Blue).",15,255);
        text("C - Toggle showing the components of the acceleration. (Orange).",15,275);
        
        text("O - Reduce the frame rate to 10 fps.",15,305);
        text("P - Restore the frame rate to 60 fps.",15,325);
        text("H - Show the help screen.",15,345);
        
        
        
        text("Try holding down left click and not moving the mouse - this will make a \"stream\" of particles that all follow the same path,",15,435);
        text("drawing a line.",15,455);
        text("Press V and A to remove the blue and red lines.",15,495);
        
        
        textAlign(CENTER, TOP);
        text("Click or press a button to continue!",width/2,550);
        
        noLoop();
      }
      else
      {
        if(mousePressed)
        {
          if(mouseButton == LEFT)
            particles.add(new Particle(wd,new PVector(mouseX, mouseY), new PVector(0,0)));
    
          if(addingAttractor)
          {
            fill(50);
            float d = clamp(dist(initialPos.x, initialPos.y, mouseX, mouseY),3);
            ellipse(initialPos.x, initialPos.y, d, d);
            fill(0);
            ellipse(initialPos.x, initialPos.y, 2, 2);
    
            if(mouseButton != RIGHT)
            {
              println(d-2);
              attractors.add(new Attractor(new PVector(initialPos.x, initialPos.y), d-2)); 
              addingAttractor = false;
            }
          }
        }
        else if(addingAttractor)
        {
          float d = clamp(dist(initialPos.x, initialPos.y, mouseX, mouseY),3);
          println(d-2);
          attractors.add(new Attractor(new PVector(initialPos.x, initialPos.y), d-2)); 
          addingAttractor = false;
        }
    
        for(int i = 0; i < attractors.size(); i++)
        {
          Attractor a = (Attractor)attractors.get(i);
          a.draw();
        }
    
        for(int i = 0; i < particles.size(); i++)
        {
          Particle p = (Particle)particles.get(i);
          p.run(attractors);
        }
      }
    }
    
    float clamp(float v, float min)
    {
      return (v<min)?min:v;
    }
    
    void wait(int milliseconds)
    {
      try
      {
        Thread.currentThread().sleep(milliseconds);
      }
      catch (InterruptedException e) { }
    }
    
    void mousePressed()
    {
      if(showHelp)
      {
        showHelp = false;
        loop();
        mousePressed = false;
      }
      
      switch(mouseButton)
      {
        //case LEFT: particles.add(new Particle(wd,new PVector(mouseX, mouseY), new PVector(0,0))); break;
      case RIGHT: 
        addingAttractor = true; 
        initialPos = new PVector(mouseX,mouseY); 
        break;
      case CENTER: 
        for(int i = 0; i < attractors.size(); i++)
        {
          Attractor a = (Attractor)attractors.get(i);
          if(dist(a.position.x, a.position.y, mouseX, mouseY) < a.getRadius())
          {
            attractors.remove(a);
            break;
          }
        }
        break;
      }
    }
    
    void keyPressed()
    {  
      if(showHelp)
      {
        showHelp = false;
        loop();
      }
      else
      {
      
      switch(key)
      {
      case 'o': 
        frameRate(10); 
        break;
      case 'p': 
        frameRate(60); 
        break;
      case 'h':
        showHelp = true;
        break;
    
      case 'a': 
        wd.showAcc = !wd.showAcc; 
        break;
      case 'v': 
        wd.showVel = !wd.showVel; 
        break;
      case 'c': 
        wd.showComps = !wd.showComps; 
        break;
    
      case 'r': 
        particles.clear(); 
        break;
      case 't': 
        attractors.clear(); 
        break;
      }
      
      }
    }
    
    

    code

    tweaks (0)

    about this sketch

    This sketch is running as Java applet, exported from Processing.

    license

    advertisement

    Callum Rogers

    Gravity Attractors

    Add to Faves Me Likey@! 14
    You must login/register to add this sketch to your favorites.

    This sketch show the complexity and chaotic nature of a multi-object gravity system. The large circular attractors can be thought of as planets with the smaller green circles as asteroids. Each planet exerts a force on each asteroid and the sum of these forces is proportional to the acceleration.

    Left click to make particles, right click to make attractors and middle click to remove attractors. Press A to display the acceleration and V for the velocity. More help is avaliable in the applet itself.

    You need to login/register to comment.