If you're seeing this message, it means we're having trouble loading external resources on our website.

If you're behind a web filter, please make sure that the domains *.kastatic.org and *.kasandbox.org are unblocked.

Lesson 5: Forces

# Mutual attraction

Hopefully, you found it helpful that we started with a simple scenario—one object attracts another object—and moved on to one object attracts many objects. However, it’s likely that you are going to find yourself in a slightly more complex situation: many objects attract each other. In other words, every object in a given system attracts every other object in that system (except for itself).
We’ve really done almost all of the work for this already. Let’s consider a program with an array of `Mover` objects:
``````var movers = [];

for (var i = 0; i < 5; i++) {
movers[i] = new Mover(
random(0.1, 2),
random(width),
random(height));
}

draw = function() {
background(255, 255, 255);
for (var i = 0; i < movers.length; i++) {
movers[i].update();
movers[i].display();
}
};``````
The `draw()` function is where we need to work some magic. Currently, we’re saying: “for every mover i, update and display yourself.” Now what we need to say is: “for every mover i, be attracted to every other mover j, and update and display yourself.”
``````for (var i = 0; i < movers.length; i++) {
// For every Mover, check every Mover!
for (var j = 0; j < movers.length; j++) {
var force = movers[j].calculateAttraction(movers[i]);
movers[i].applyForce(force);
}
}

for (var i = 0; i < movers.length; i++) {
movers[i].update();
movers[i].display();
}``````
Notice that we made an entirely new `for` loop above the update-and-display loop. That's because we want to make sure that we calculate all the attraction forces before updating each mover. If we accidentally updated each mover in that first `for` loop, then we'd be affecting the calculation of the attraction forces after, and they wouldn't be accurate.
Our code won't work yet, because we need each `Mover` to have a `calculateAttraction()` method. In the previous example, we had an `Attractor` object with a method named `calculateAttraction()`. Now, since we have movers attracting movers, we can copy that method into the `Mover` object:
``````Mover.prototype.calculateAttraction = function(m) {
var force = PVector.sub(this.position, m.position);
var distance = force.mag();
distance = constrain(distance, 5.0, 25.0);
force.normalize();

var strength = (G * this.mass * m.mass) / (distance * distance);
force.mult(strength);
return force;
};``````
Of course, there’s one small problem. When we are looking at every mover i and every mover j, are we OK with the times that i equals j? For example, should mover #3 attract mover #3? The answer, of course, is no. If there are five objects, we only want mover #3 to attract 0, 1, 2, and 4, skipping itself. We do, however, want to calculate and apply both the force from mover #3 on mover #1, and mover #1 on mover #3. The calculated forces will be the same for the pair, but the resulting acceleration will be different, depending on the mass of each mover. Our attraction table should look like:
0 ⇢ 1, 2, 3, 4
1 ⇢ 0, 2, 3, 4
2 ⇢ 0, 1, 3, 4
3 ⇢ 0, 1, 2, 4
And so, we finish this example by modifying our for loop so that the inner loop avoids movers attracting themselves:
``````for (var i = 0; i < movers.length; i++) {
for (var j = 0; j < movers.length; j++) {
if (i !== j) {
var force = movers[j].calculateAttraction(movers[i]);
movers[i].applyForce(force);
}
}
}``````
Let's see it all together now:

This "Natural Simulations" course is a derivative of "The Nature of Code" by Daniel Shiffman, used under a Creative Commons Attribution-NonCommercial 3.0 Unported License.

## Want to join the conversation?

• Oh my god, I solved this challenge by typing one character!
• Set the gravity constant to something less than 0!
(1 vote)
• Hello! Can anyone help guide me in the right direction as to what I should be looking for to fill in these blanks:

Mover.prototype.calculateAttraction = function(m) {
____;
var strength = ____;
____;
};
? I'm pretty sure I got the force.mult(-1*strength); part right, but I don't know where to look to fill in these blanks from the hint! Thanks :).
• You need to put a minus sign before the G (well, as we are dealing with vectors, putting a minus changes the direction, putting a minus before G changes the answer for the force from positive to negative, from attraction to repulsion)
• why in the line 30 ( Mover.prototype.calculateAttraction = function(m,i) {) the function is accepting two parameters ? i see the m used inside the function, but i not see the i being used :/
• Is it important the order in the methods, when creating the object? I mean at the beggining of the code, not at the `draw function`. I've realized the `.display` is usually after the `.applyForce` and the `update`methods.
• The order of methods and properties do not matter.
• Is it possible for an object to be attracted to another object (like in the gravity examples) when it is within a certain distance, but when it is outside of that distance, it moves randomly (like in the walker examples)?
I've tried using PVector.sub to calculate the distance but I'm not sure where I would put the if function...
for example:

if (within certain distance) {
calculate attraction}
else {
move randomly}

here is my actual code that I tried putting within the draw function:
(I know the problem is in this part because both the attraction and random movement work when used individually)

for (var i = 0; i < movers.length; i++) {
var force = attractor.calculateAttraction(movers[i]);
if (force<100) {
movers[i].applyForce(force);
} else {
movers[i].update();
}
movers[i].checkEdges();
movers[i].display();
}

any tips?
thanks
• In this last example on mutual attraction there are three loops, one outside the draw function and two inside. I'm getting lost following the logic. Could someone give me an explanation foor each.
Thank you.
(1 vote)
• First, you make a bunch of Movers. 5 of them in fact.
You want to make them only once, otherwise you'll end up with thousands. :P So you do that outside the draw function.

Then, each Mover is attracted to each other mover.
You could draw a table:
``  | 0  1  2  3  4--+--------------0 | x  o  o  o  o1 | o  x  o  o  o2 | o  o  x  o  o3 | o  o  o  x  o4 | o  o  o  o  x``
Where there's an o, the two movers attract each other.
So for each Mover in in the left column, you find the attraction for each Mover in the upper row: two nested for loops.
• Just put a minus sign before the 1 and after the = on line 1
• `===` checks whether two things are equal.
`!==` checks whether two things are not equal.