Mutual attraction of objects

#1

Hello,
I am trying to take a different approach and use functions instead of classes to recreate the mutual attraction sketch from Nature of code (ch2.08 to be specific).I have taken a different approach,I am confident the basics do work since i’m able to get a sphere attract itself to the mouse pointer and follow it around.

I tried to use the nested Loop method in a different manner but the results are completely off.The circles almost teleport to the top left corner (0,0).It most like is a logical error on my part and any help will greatly be appreciated.

The reason i added the netForce() function is so that i can easily switch between having multiple circles follow the mouse pointer (this works ) and between the circles attracting each other(this doesn’t).

var particles = []; // various particles are stored in this array
function setup(){
    var width = windowWidth;
    var height = windowHeight;
    createCanvas(width, height);
    p = new particle();
    n = new netForce();
    //particles.push(p);

}
function mouseClicked(){
    p = new particle(); // when user clicks a new particle is formed
    particles.push(p); // particle is added to the array
 }
function draw(){
    background(200);
    for(i=0;i<particles.length;i++){
    particles[i].main();
    n.dir(particles[i]);
    
    
    }


}

function particle(){
    
    this.maxvelocity =5;     ///
    this.maxforce = 0.5;     //
    this.velocity = createVector(0,0);
    this.location = createVector(random(width),random(height)); // random initial location for each object
    this.targetMouse = 1;  //1 = yes 0 = no(no results in mutual attraction which is borked)
    this.target = createVector();
    this.dir = createVector();
    
    this.origin = createVector(0,0);
    this.acceleration = createVector(0,0);
    
    this.display = function(){  // To display the object 
        
        circle(this.location.x,this.location.y,100);
    }

   this.acquireDir = function(direction){ // acquires the direction to the target

            this.dir = direction.sub(this.location);
            this.dir.normalize();    
            
            
            this.addForce(this.dir); // Pass the direction vector to be added to the acceleration
            
        }

   this.motion = function(){  // this function is responsible for providing the force
       
       
        this.velocity.add(this.acceleration);
        this.velocity.limit(this.maxvelocity);
        this.acceleration.mult(0);
    }

    this.addForce = function(force){
        this.acceleration.add(force);
    }

    this.update = function(){  // updates the location of the object
       
        this.location.add(this.velocity);
        
       
    }
    this.main = function(){   
        this.display();
        this.motion();
        this.update();
        
    }
    
}
function netForce(){
    
    this.dir = function(){
        
        
    
        if(particles[i].targetMouse == true){   // This if statement works as expectec
            //particles[i].target = createVector(mouseX,mouseY);
            this.mouse = createVector(mouseX,mouseY); // The target is the mouse only if targetMouse =1
            //particles[i].acquireDir(this.mouse);
            particles[i].target = this.mouse;
            particles[i].acquireDir(particles[i].target);
        
        }

        if(particles[i].targetMouse == false){  //  Mutual repulsion  // this doesn't work
             for(j=0;j<particles.length;j++){
                if(i!=j){
                particles[i].acquireDir(particles[j].location);
             }
            }
        }
    }
    }

p5.js online editor version of the code

you need to change the value of targetMouse = 0 in particle function,this is when mutual attraction is supposed to take place.Any advice or tips will be greatly appreciated.

1 Like
#2

there are a few problems with your code. the main problem is you’re subtracting the location from the direction var you pass into your acquireDir function. i made some adjustments and it now works as it should i believe.

var netForce;
var particles = []; // various particles are stored in this array
function setup() {
  var width = windowWidth;
  var height = windowHeight;
  createCanvas(width, height);
  netForce = new NetForce();
}

function mouseClicked() {
  p = new particle(); // when user clicks a new particle is formed
  particles.push(p); // particle is added to the array
}

function draw() {
  background(200);
  for (i = 0; i < particles.length; i++) {
    var p1 = particles[i];
    p1.main();
    netForce.dir(p1);
  }
}

function particle() {
  this.maxvelocity = 5; ///
  this.maxforce = 0.5; //
  this.velocity = createVector(0, 0);
  this.location = createVector(random(width), random(height)); // random initial location for each object
  this.targetMouse = 0; //1 = yes 0 = no(no results in mutual attraction which is borked)
  this.target = createVector();
  this.dir = createVector();

  this.origin = createVector(0, 0);
  this.acceleration = createVector(0, 0);

  this.display = function() { // To display the object 
    circle(this.location.x, this.location.y, 100);
  }

  this.acquireDir = function(direction) { // acquires the direction to the target

    this.dir = p5.Vector.sub(direction, this.location);
    this.dir.normalize();

    this.addForce(this.dir); // Pass the direction vector to be added to the acceleration
  }

  this.addForce = function(force) {
    this.acceleration.add(force);
  }

  this.update = function() { // updates the location of the object
    this.velocity.add(this.acceleration);
    this.velocity.limit(this.maxvelocity);
    this.acceleration.mult(0);
    this.location.add(this.velocity);
  }
  this.main = function() {
    this.update();
    this.display();
  }
}

function NetForce() {
  this.dir = function() {
    for (var i = 0; i < particles.length; i++) {
      var p1 = particles[i];
      if (p1.targetMouse == true) { // This if statement works as expectec
        var mv = createVector(mouseX, mouseY); // The target is the mouse only if targetMouse =1
        p1.acquireDir(mv);
      }
      else { //  Mutual repulsion  // this doesn't work          
        for (var j = 0; j < particles.length; j++) {
          if (i === j) continue;
          var p2 = particles[j];
          
          p1.acquireDir(p2.location);
        }
      }
    }
  }
}
2 Likes
#3

Thanks a lot, It finally runs as intended.

this.dir = direction.sub(this.location);
this.dir = p5.Vector.sub(direction, this.location);

Is the first piece of code wrong as it stores the vector(location - drection) in the variable this.dir rather than (direction - location) and i might be wrong but doesn’t the second line of code return the subtracted value which is stored in this.dir or does using p5.Vector.sub work differently?
Thanks a lot for the help :grinning:

#4

taken from the p5.Vector source

Subtracts x, y, and z components from a vector, subtracts one vector from
another, or subtracts two independent vectors. The version of the method
that subtracts two vectors is a static method and returns a p5.Vector, the
other acts directly on the vector. See the examples for more context.

1 Like
#5

Ahhh, That makes sense.Thanks