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

Vector motion

All this vector math stuff sounds like something we should know about, but why? How will it actually help us write code? The truth of the matter is that we need to have some patience. It will take some time before the awesomeness of using the PVector class fully comes to light.
This is actually a common occurrence when first learning a new data structure. For example, when you first learn about an array, it might seem like much more work to use an array than to just have several variables stand for multiple things. But that plan quickly breaks down when you need a hundred, or a thousand, or ten thousand things.
The same can be true for PVector. What might seem like more work now will pay off later, and pay off quite nicely. And you don’t have to wait too long, as your reward will come in the next chapter.

Velocity

For now, however, we want to focus on simplicity. What does it mean to program motion using vectors? We’ve seen the beginning of this in the bouncing ball example. An object on screen has a position (where it is at any given moment) as well as a velocity (instructions for how it should move from one moment to the next). Velocity is added to position:
position.add(velocity);
And then we draw the object at that position:
ellipse(position.x, position.y, 16, 16);
This is Motion 101:
  • Add velocity to position
  • Draw object at position
In the bouncing ball example, all of this code happened inside the ProcessingJS's draw function. What we want to do now is move towards encapsulating all of the logic for motion inside of an object. This way, we can create a foundation for programming moving objects in all of our ProcessingJS programs.
In this case, we’re going to create a generic Mover object that will describe a thing moving around the screen. And so we must consider the following two questions:
  • What data does a mover have?
  • What functionality does a mover have?
Our Motion 101 algorithm tells us the answers to these questions. A Mover object has two pieces of data: position and velocity, which are both PVector objects. We can start by writing the constructor function that initializes those properties to appropriate random values:
var Mover = function() {
  this.position = new PVector(random(width), random(height));
  this.velocity = new PVector(random(-2, 2), random(-2, 2));
};
Its functionality is just about as simple. The Mover needs to move and it needs to be seen. We’ll implement these needs as methods named update() and display(). We’ll put all of our motion logic code in update() and draw the object in display().
Mover.prototype.update = function() {
  this.position.add(this.velocity);
};

Mover.prototype.display = function() {
  stroke(0);
  strokeWeight(2);
  fill(127);
  ellipse(this.position.x, this.position.y, 48, 48);
};
If object-oriented programming is at all new to you, one aspect here may seem a bit confusing. After all, we spent the beginning of this chapter discussing PVector. The PVector object is the template for making the position object and the velocity object. So what are they doing inside of yet another object, the Mover object? In fact, this is just about the most normal thing ever. An object is simply something that holds data (and functionality). That data can be numbers, strings, arrays or other objects! We’ll see this over and over again in this course. For example, in the Particles tutorial, we’ll write an object to describe a system of particles. That ParticleSystem object will have as its data an array of Particle objects…and each Particle object will have as its data several PVector objects!
Let’s finish off the Mover object by incorporating a function to determine what the object should do when it reaches the edge of the window. For now let’s do something simple, and just have it wrap around the edges:
Mover.prototype.checkEdges = function() {

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

  if (this.position.y > height) {
    this.position.y = 0;
  } 
  else if (this.position.y < 0) {
    this.position.y = height;
  }
};
Now that the Mover object is finished, we can look at what we need to do in our main program. We first declare and initialize new Mover instance:
var mover = new Mover();
Then we call the appropriate functions in draw:
draw = function() {
  background(255, 255, 255);

  mover.update();
  mover.checkEdges();
  mover.display(); 
};
Here's the full running example. Try playing around with the numbers, commenting out code, and seeing what happens:

Acceleration

OK. At this point, we should feel comfortable with two things: (1) what a PVector is and (2) how we use PVectors inside of an object to keep track of its position and movement. This is an excellent first step and deserves a mild round of applause. Before standing ovations and screaming fans, however, we need to make one more, somewhat bigger step forward. After all, watching the Motion 101 example is fairly boring—the circle never speeds up, never slows down, and never turns. For more interesting motion, for motion that appears in the real world around us, we need to add one more PVector to our Mover object—acceleration.
The strict definition of acceleration we’re using here is: the rate of change of velocity. Let’s think about that definition for a moment. Is this a new concept? Not really. Velocity is defined as the rate of change of position. In essence, we are developing a “trickle-down” effect. Acceleration affects velocity, which in turn affects position (for some brief foreshadowing, this point will become even more crucial in the next chapter, when we see how forces affect acceleration, which affects velocity, which affects position). In code, this reads:
velocity.add(acceleration);
position.add(velocity);
As an exercise, from this point forward, let’s make a rule for ourselves. Let’s write every example in the rest of these tutorials without ever touching the value of velocity and position (except to initialize them). In other words, our goal now for programming motion is: Come up with an algorithm for how we calculate acceleration and let the trickle-down effect work its magic. (In truth, you’ll find reasons to break this rule, but it’s important to illustrate the principles behind our motion algorithm.) And so we need to come up with some ways to calculate acceleration:
  1. A constant acceleration
  2. A totally random acceleration
  3. Acceleration towards the mouse
Algorithm #1, a constant acceleration, is not particularly interesting, but it is the simplest and will help us begin incorporating acceleration into our code.
The first thing we need to do is add another PVector property to the Mover constructor to represent the acceleration. We'll initialize it to (0.001,0.01) and keep it at that value forever, since our current algorithm is constant acceleration. You might be thinking, “Gosh, those values seem awfully small!” That’s right, they are quite tiny. It’s important to realize that our acceleration values (measured in pixels) will accumulate over time in the velocity, about thirty times per second depending on our sketch’s frame rate. And so to keep the magnitude of the velocity vector within a reasonable range, our acceleration values should start and remain quite small.
var Mover = function() {
  this.position = new PVector(width/2,height/2);
  this.velocity = new PVector(0, 0);
  this.acceleration = new PVector(-0.001, 0.01);
};
Notice above that we also started the velocity at 0 - because we know we'll be speeding it up as the program runs, thanks to acceleration. We'll do that in the update() method:
Mover.prototype.update = function() {
  this.velocity.add(this.acceleration);
  this.position.add(this.velocity);  
};
Since we are continuously increasing velocity, we run the risk of our velocity values becoming incredibly large, if we leave the program running long enough. We want to limit the velocity to a maximum. We can do that using the PVector limit method, which restricts a vector to a given magnitude.
Mover.prototype.update = function() {
  this.velocity.add(this.acceleration);
  this.velocity.limit(10);
  this.position.add(this.velocity);  
};
This translates to the following:
What is the magnitude of velocity? If it’s less than 10, no worries; just leave it as is. If it’s more than 10, however, reduce it to 10!
Let’s take a look at the changes to the Mover object, complete with acceleration and limit():
Now on to Algorithm #2, a totally random acceleration. In this case, instead of initializing acceleration in the object’s constructor, we want to pick a new acceleration each cycle, i.e. each time update() is called.
Mover.prototype.update = function() {
  this.acceleration = PVector.random2D();
  this.velocity.add(this.acceleration);
  this.velocity.limit(10);
  this.position.add(this.velocity);  
};
Because the random vector is a normalized one, we can try scaling it with two different techniques:
  1. scaling the acceleration to a constant value:
    acceleration = PVector.random2D();
    acceleration.mult(0.5);
    
  1. scaling the acceleration to a random value:
    acceleration = PVector.random2D();
    acceleration.mult(random(2));
    
While this may seem like an obvious point, it’s crucial to understand that acceleration does not merely refer to the speeding up or slowing down of a moving object, but rather any change in velocity in either magnitude or direction. Acceleration is used to steer an object, and we’ll see this again and again in future chapters as we begin to program objects that make decisions about how to move about the screen.

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?

  • hopper cool style avatar for user Rathony
    I am having trouble with the next challenge, the Braking Car.
    I am on step 3, where you have to stop the car's velocity from going below 0.
    At the moment, I have:
    Car.prototype.update = function() {
    if(this.velocity.x < 0) {
    this.acceleration.set(0,0);
    }
    this.velocity.add(this.acceleration);
    this.velocity.limit(10);
    this.position.add(this.velocity);
    };

    This code does stop the car from going backwards, but it is not accepted. Does anyone know what I have done wrong?
    (50 votes)
    Default Khan Academy avatar avatar for user
  • blobby green style avatar for user Wings94
    SPOILERS FOR CHALLENGE


    Hello. I finished the Braking Car challenge, but I was wondering if someone could explain the difference in code between something in a different order. In the update() method of the challenge, I initially had:
    this.velocity.add(this.acceleration);
    this.velocity.limit(10);
    this.position.add(this.velocity);
    if (this.velocity.x < 0) {
    this.velocity.x = 0;
    }
    This didn't work. It brought the velocity to a very low number, but it didn't bring it to 0. But when I did this:
    this.velocity.add(this.acceleration);
    this.velocity.limit(10);
    if (this.velocity.x < 0) {
    this.velocity.x = 0;
    }
    this.position.add(this.velocity);
    It worked. It brought the velocity to 0. Why is this? What did the difference in ordering do to the program so that it worked? I appreciate any help with this. Thanks.
    (32 votes)
    Default Khan Academy avatar avatar for user
    • leafers ultimate style avatar for user Diogo Ribeiro
      I only saw this question now, and it's a great question. If you are braking, your acceleration is negative; if the car stopped, it has velocity 0.
      Using this, take a look a what happens: acceleration is added to velocity, so your velocity is now also negative. You then use this negative velocity's value and sum it to position. It's only after the value has been used that the correction kicks in bringing the value of velocity back to 0. But it's too late, as we already used the wrong value.

      On the second example, your correction brings velocity value back to 0 BEFORE it has been used, which is the correct way to do it.

      This actually happens a lot in programs in the most diverse areas, and these errors are usually hard to find. What you should do ALWAYS is perform the consistency checks right after changing the values, or at most before using values that might pssibly be wrong.

      I hope that makes sense :D
      (27 votes)
  • spunky sam blue style avatar for user ali_shabrawy1
    what does the random2D( ); function do ?
    (21 votes)
    Default Khan Academy avatar avatar for user
  • leaf green style avatar for user ☣The Reckoning☣(OFFLINE)
    for the car braking challenge, I see people using car.acceleration.set. What's "set"? I don't remember seeing that in the lesson...
    (8 votes)
    Default Khan Academy avatar avatar for user
  • ohnoes default style avatar for user Becky
    I feel like I pretty much understand this section, but I am still baffled by the following challenge. If we have a vector in an object & we want to change it according to user input (like keyPressed), how do we do that properly? I've tried creating a new vector, adding to the existing vector, & adding an argument to the update function (all of which sort of get the job done but not how the challenge wants us to apparently cause I cant get past step one) - any help would be greatly appreciated! & BTW THANK YOU FOR THIS AWESOME NEW CONTENT KHAN PEEPS!
    (6 votes)
    Default Khan Academy avatar avatar for user
    • leaf green style avatar for user Lucie le Blanc
      Try using keyIsPressed instead of keyPressed. I got stuck on step one as well because of it. The user @EMC is also correct in that you need to use an if statement and include the car.acceleration.set(..., ...) function. Here's what mine looks like right now:
      if (keyIsPressed && keyCode === RIGHT){
      car.acceleration.set(1, 0);
      } else {
      car.acceleration.set(0, 0);
      }
      (11 votes)
  • sneak peak blue style avatar for user Patrick Jarrold
    Why doesn't setting the acceleration to (0, 0) in the update function eventually stop the car?
    (7 votes)
    Default Khan Academy avatar avatar for user
    • piceratops ultimate style avatar for user ankurec01
      Setting the acceleration to 0 doesn't change the velocity. Acceleration is the increase in velocity and setting the acceleration to 0 keeps the velocity constant. So if the car was moving at say, 59 KMPH, setting the acceleration to 0 would keep the car moving at 59 KMPH. Sorry for being late but hope this helps someone else.
      (1 vote)
  • old spice man green style avatar for user Elijah Daniels
    Why is it called a PVector? What does the P stand for?
    (9 votes)
    Default Khan Academy avatar avatar for user
  • leaf green style avatar for user appinv
    What is the use of random 2D? Why not use just random?
    (2 votes)
    Default Khan Academy avatar avatar for user
  • sneak peak blue style avatar for user Patrick Jarrold
    Aren't there some mathematical equations used in physics that look a lot like location.add(velocity) and velocity.add(acceleration)?
    (3 votes)
    Default Khan Academy avatar avatar for user
    • blobby green style avatar for user Dean Smith
      I think you cannot use physical formulas because physical functions depend explicitly on a parameter like time: f(t)= c*t^2 (function ist continuous and has a complete domain)
      Computer languages tend to use dicrete recursive defitions of functions without a (t) parametrization:
      You can check out the recursive definitions of functions on a certain playlisst on khan academy, probably on the pre-calc playlist.

      I'll try to give you an example so you get the idea. f(x)=x^2 explizit paremetrization
      A(n+1)= 2n+1 + An , n= 0,1,2,3,... and A0 :=0

      If i defined it correctly, both functions give you the same numbers: 1, 4, 9, 16, 25 as in a quadratic function. Theoretically all physical formulas must be defined recursively in order to be used by the computer.
      (3 votes)
  • orange juice squid orange style avatar for user Omeleto
    Pleaase help me with my experimental project: does loops "for" with arrays can be applied to PVector, in order for us to have multiple objects with different positions and velocity?
    (2 votes)
    Default Khan Academy avatar avatar for user