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.

Main content

Motion of many objects

In the real world, the one we're seeking inspiration from here, we have more than one moving object - we're surrounded by many objects of varying mass and position. Let's look at how we can get our Mover to better simulate that aspect of the real world.
To do this, we’ll need a quick review of object-oriented programming. Again, we’re not covering all the basics of OO programming here. However, since the idea of creating a world filled with objects is pretty fundamental to all the examples in this course, it’s worth taking a moment to walk through the steps of going from one object to many.
As a reminder, this is what our current Mover looks like. It is identical to the Mover object that we created when we first introduced vectors, but with two additions—mass and a new applyForce() method:
Now that our object is set, we can choose to create, say, twenty Mover instances with an array, initializing them with a loop
var movers = [];

for (var i = 0; i < 20; i++) {
    movers[i] = new Mover();
}
But now we have a small issue. If we refer back to the Mover object’s constructor…
var Mover = function() {
    this.mass = 1;
    this.position = new PVector(30, 30);
    this.velocity = new PVector(0, 0);
    this.acceleration = new PVector(0, 0);
};
…we discover that every Mover object is made exactly the same way. What we want are Mover objects with varying mass that start at varying positions. Here is where we need to increase the sophistication of our constructor by adding arguments.
var Mover = function(m, x, y) {
    this.mass = m;
    this.position = new PVector(x, y);
    this.velocity = new PVector(0, 0);
    this.acceleration = new PVector(0, 0);
};
Notice how the mass and position are no longer set to hardcoded numbers, but rather initialized via arguments passed through the constructor. This means we can create a variety of Mover objects: big ones, small ones, ones that start on the left side of the screen, ones that start on the right, etc.
// A big Mover on the left side of the window
var m1 = new Mover(10, 0, height/2);
// A small Mover on the right side of the window
var m2 = new Mover(0.1, width, height/2);
With an array, however, we want to initialize all of the objects with a loop.
for (var i = 0; i < 20; i++) {
    movers[i] = new Mover(random(0.1, 5), 0, 0);
}
For each mover created, the mass is set to a random value between 0.1 and 5, the starting x-position is set to 0, and the starting y-position is set to 0. Certainly, there are all sorts of ways we might choose to initialize the objects; this is just a demonstration of one possibility.
Once the array of objects is declared, created, and initialized, the rest of the code is simple. We run through every object, hand them each the forces in the environment, and enjoy the show.
draw = function() {
  background(50, 50, 50);

  for (var i = 0; i < movers.length; i++) {
    var wind = new PVector(0.01, 0);
    var gravity = new PVector(0, 0.1);
    movers[i].applyForce(wind);
    movers[i].applyForce(gravity);
    movers[i].update();
    movers[i].display();
    movers[i].checkEdges();
  }
};
Here's how the program looks, all together. Note how in the program, the smaller circles reach the right of the window faster than the larger ones. This is because of our formula: acceleration = force divided by mass. The larger the mass, the smaller the acceleration.

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?

  • piceratops ultimate style avatar for user Owen S
    How would we check for collisions with the balls against each other? Is there a way to check: if the balls hit each other, then they bounce away from each other? Thanks!
    (24 votes)
    Default Khan Academy avatar avatar for user
    • leaf grey style avatar for user Gregory G
      (I'd imagine it'd be a bit more complicated for an ellipse which isn't a perfect circle)
      Lets just say we circles A and B, with their locations being represented as PVector A and B. Lets just say that they also have radius A and B. We'd check the distance between them (dist(A.x, A.y, B.x, B.y)) and add their radii. If distance <= A+B, we know they have collided. If not, they have not collided. I hope this helps.
      (30 votes)
  • leaf green style avatar for user raph
    Challenge: Wall balls. Step 1 - Error...Make sure the balls are bouncing in a sensible direction? What am I missing?
    (17 votes)
    Default Khan Academy avatar avatar for user
  • hopper jumping style avatar for user dallashaase
    On the Walls Balls challenge it gives me: "That's a great way to get the balls to bounce back away from the walls! However, in this case, we actually want to generate a force vector that we can apply, whose effects will be combined with the other forces."

    I don't understand what else I'm meant to do... I have it working just fine in my eyes...
    (6 votes)
    Default Khan Academy avatar avatar for user
  • hopper cool style avatar for user Isaac A.
    I'm on the 2nd part could some1 help me thanks
    here's my original code:
    var Ball = function(m, x, y) {
    this.mass = m;
    this.position = new PVector(x, y);
    this.velocity = new PVector(0, 0);
    this.acceleration = new PVector(0, 0);
    this.color = color(random(255), random(255), random(255), 127);
    };

    Ball.prototype.applyForce = function(force) {
    var f = PVector.div(force, this.mass);
    this.acceleration.add(f);
    };

    Ball.prototype.update = function() {
    this.velocity.add(this.acceleration);
    this.position.add(this.velocity);
    this.acceleration.mult(0);
    };

    Ball.prototype.checkEdges = function() {
    if (this.position.x > width) {
    this.position.x = width;
    this.velocity.x *= -1;
    } else if (this.position.x < 0) {
    this.velocity.x *= -1;
    this.position.x = 0;
    }
    if (this.position.y > height) {
    this.velocity.y *= -1;
    this.position.y = height;
    }
    };

    Ball.prototype.display = function() {
    stroke(0);
    strokeWeight(2);
    fill(this.color);
    ellipse(this.position.x, this.position.y, this.mass*16, this.mass*16);
    };

    Ball.prototype.calculateWallForce = function() {
    var x = 0;
    var y = 0;
    if (this.position.x > width) {
    x = -1;
    } else if (this.position.x < 0) {
    x = 1;
    }

    if (this.position.y > height) {
    y = -1;
    } else if (this.position.y < 0) {
    y = 1;

    }

    return new PVector(x, y);
    };

    var balls = [];

    for (var i = 0; i < 20; i++) {
    balls[i] = new Ball(random(0.1, 5), 0, 0);
    }

    var draw = function() {
    background(255, 255, 255);

    for (var i = 0; i < balls.length; i++) {
    var wind = new PVector(0.01, 0);
    var gravity = new PVector(0, 0.1);
    balls[i].applyForce(wind);
    balls[i].applyForce(gravity);
    balls[i].update();
    balls[i].display();

    }
    };
    (7 votes)
    Default Khan Academy avatar avatar for user
  • orange juice squid orange style avatar for user jason.ileto
    Having trouble with the second step of Wall Balls challenge. The hint says to calculate the force within the loop but isn't force calculated in the applyForce prototype? What are we supposed to do in this step?
    (4 votes)
    Default Khan Academy avatar avatar for user
  • boggle green style avatar for user Chris A.
    In the example above they re-declare wind and gravity inside a loop, inside draw.
    This seems pretty redundant since there seems to be no reason for doing so. Am I missing something or is it necessary for some other reason?
    (4 votes)
    Default Khan Academy avatar avatar for user
  • old spice man blue style avatar for user Horse Rider
    i am stuck on step 2 of wall balls
    Here is my code:
    var Ball = function(m, x, y) {
    this.mass = m;
    this.position = new PVector(x, y);
    this.velocity = new PVector(0, 0);
    this.acceleration = new PVector(0, 0);
    this.color = color(random(255), random(255), random(255), 127);
    };

    Ball.prototype.applyForce = function(force) {
    var f = PVector.div(force, this.mass);
    this.acceleration.add(f);
    };

    Ball.prototype.update = function() {
    this.velocity.add(this.acceleration);
    this.position.add(this.velocity);
    this.acceleration.mult(0);
    };

    Ball.prototype.display = function() {
    stroke(0);
    strokeWeight(2);
    fill(this.color);
    ellipse(this.position.x, this.position.y, this.mass * 16, this.mass * 16);
    };

    Ball.prototype.calculateWallForce = function() {
    var x = 0;
    var y = 0;

    if (this.position.x > width) {
    x = -1;
    } else if (this.position.x < 0) {
    x = 1;
    }

    if (this.position.y > height) {
    y = -1;
    } else if (this.position.y < 0) {
    y =1;
    }
    return new PVector(x,y);

    };

    var balls = [];

    for (var i = 0; i < 20; i++) {
    balls[i] = new Ball(random(0.1, 5), 0, 0);
    }

    var wind = new PVector(0.01, 0);
    var gravity = new PVector(0, 0.1);

    draw = function() {
    background(255, 255, 255);

    for (var i = 0; i < balls.length; i++) {
    balls[i].applyForce(wind);
    balls[i].applyForce(gravity);
    balls[i].update();
    balls[i].display();
    }
    };
    (5 votes)
    Default Khan Academy avatar avatar for user
  • winston default style avatar for user Jared O'Leary
    In the examples above, if gravity is a change in the Y position, and wind is a change in the X position, why do we need them as two separate PVectors? Couldn't the examples above just have one PVector that changes both the X (wind) and the Y (gravity)?
    (4 votes)
    Default Khan Academy avatar avatar for user
  • leafers ultimate style avatar for user Teo
    In the wall balls challenge what do I have to do to my first and second variable when the balls hit a wall, ceiling or floor.
    (3 votes)
    Default Khan Academy avatar avatar for user
    • blobby green style avatar for user dvdweed1
      For that challenge I found it easier to do the second part first, where you apply the force you calculated to the balls in the draw function. This gave me immediate feedback as to what the values I was changing in the calculateWallForce function was doing to the balls.
      (3 votes)
  • leaf orange style avatar for user apex [still active]
    In the code snippets Pamela gives, she uses a for-loop to generate 20 balls. Here is where I get confused. She did this:
    movers[i] = new Mover(random(0.1, 5), 0, 0);
    Whereas I would've done this:
    movers.push(new Mover(random(0.1, 5), 0, 0));

    When I see Pamela's code, it makes me think: won't that override the previous balls in the array?

    Is it because she uses [i]?

    Some answers would be appreciated :D
    (1 vote)
    Default Khan Academy avatar avatar for user
    • spunky sam blue style avatar for user Dalendrion
      var movers = [];

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


      The first time, i = 0.
      So we add a new Mover to movers[0]. The array is now:
      movers = [new Mover(...)].
      There is now a mover at the zeroth index.

      The second time, i = 1.
      So we add a new Mover to movers[1]. The array is now:
      movers = [new Mover(...), new Mover(...)].
      There are now movers at the zeroth and first indices.

      And so on until i = 19. Then i becomes 20 and the loop stops.
      (6 votes)