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

Interactive vector motion

To finish out this section, let’s try something a bit more complex and a great deal more useful. We’ll dynamically calculate an object’s acceleration according to a rule stated in Algorithm #3 — the object accelerates towards the mouse.
Diagram of mouse acceleration vector
Anytime we want to calculate a vector based on a rule or a formula, we need to compute two things: magnitude and direction. Let’s start with direction. We know the acceleration vector should point from the object’s position towards the mouse position. Let’s say the object is located at the point (x,y) and the mouse at (mouseX,mouseY).
Diagram of dx, dy
In that diagram, we see that we can get a vector (dx,dy) by subtracting the object’s position from the mouse’s position.:
  • dx = mouseX - x
  • dy = mouseY - y
Let’s rewrite the above using PVector syntax. Assuming we are in the Mover object definition and thus have access to the object’s PVector position, we then have:
var mouse = new PVector(mouseX, mouseY);
// Look! We’re using the static sub() because we want a completely new PVector
var dir = PVector.sub(mouse, position);
We now have a PVector that points from the mover’s position all the way to the mouse. If the object were to actually accelerate using that vector, it would appear instantaneously at the mouse position. This does not make for good animation, of course, and what we want to do now is decide how quickly that object should accelerate toward the mouse.
In order to set the magnitude (whatever it may be) of our acceleration PVector, we must first ___ that direction vector. That’s right, you said it. Normalize. If we can shrink the vector down to its unit vector (of length one) then we have a vector that tells us the direction and can easily be scaled to any value. One multiplied by anything equals anything.
var anything = ??;
dir.normalize();
dir.mult(anything);
To summarize, we take the following steps:
  1. Calculate a vector that points from the object to the target position (mouse)
  2. Normalize that vector (reducing its length to 1)
  3. Scale that vector to an appropriate value (by multiplying it by some value)
  4. Assign that vector to acceleration
Here's what the program looks like, with those steps fully implemented:
You may be wondering why the circle doesn’t stop when it reaches the target. It’s important to note that the object moving has no knowledge about trying to stop at a destination; it only knows where the destination is and tries to go there as quickly as possible. Going as quickly as possible means it will inevitably overshoot the position and have to turn around, again going as quickly as possible towards the destination, overshooting it again, and so on and so forth. Stay tuned; in later sections we’ll learn how to program an object to arrive at a position (slow down on approach).
This example is remarkably close to the concept of gravitational attraction (in which the object is attracted to the mouse position). Gravitational attraction will be covered in more detail in the next section. However, one thing missing here is that the strength of gravity (magnitude of acceleration) is inversely proportional to distance. This means that the closer the object is to the mouse, the faster it accelerates.
Let’s see what this example would look like with an array of movers (rather than just one).

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?

  • male robot hal style avatar for user Christopher
    how to find the biggest possible direction vector compared to the current one?
    (21 votes)
    Default Khan Academy avatar avatar for user
  • blobby green style avatar for user Alejandro Caicedo
    In the mouse stalker I cant continue, I dont know how to answer it, could some one help me.
    (17 votes)
    Default Khan Academy avatar avatar for user
  • leafers ultimate style avatar for user Teo
    OK I think I almost got it. Thank you for your patience with me. I think that what closeness is something like this.
    var closeness = (dir.mag()-???)/maxMag;

    But I'm not sure what to subtract from dir.mag()? I'm sure it's painfully obvious but I can't see it.
    (3 votes)
    Default Khan Academy avatar avatar for user
    • male robot johnny style avatar for user Marc Isaacson
      The hint tells you that 0 should indicate that it is the farthest away and 1 should indicate that it's right on top.

      maxMag is a fixed value. So, the only thing that is changing in that equation ((maxMag - dir.mag()) / maxMag)) is dir.mag(). Think about how dir.mag() is calculated. You created the dir vector to be a new PVector that is the difference between the mouse location and the object. The closer that the object is to the mouse location, the smaller the dir vector will be. The smaller that the direction vector is, the smaller its magnitude will be.

      As the magnitude of the dir vector gets smaller and smaller, you are subtracting less and less from maxMag. Therefore, the formula will yield a result that is closer and closer to 1. Conversely, as the object is further away from the mouse, the formula will yield a result that gets closer and closer to zero (as the magnitude of the dir vector gets closer and closer to the magnitude (maxMag) of the largest direction vector (maxDir)).
      (36 votes)
  • leafers sapling style avatar for user Benq
    I'm stuck on the last part of challenge: mouse stalker. Here is the code:

    Mover.prototype.update = function() {
    var mouse = new PVector(mouseX, mouseY);
    var dir = PVector.sub(mouse, this.position);
    var closeness = (maxMag-dir.mag())/maxMag;
    dir.normalize();
    dir.mult(closeness);

    this.acceleration = dir;
    this.velocity.add(this.acceleration);
    this.velocity.limit(5);
    this.position.add(this.velocity);
    };

    When I entered dir.mult(closeness);, the ball just went to the upper left corner. How do I fix this?
    (8 votes)
    Default Khan Academy avatar avatar for user
  • leafers ultimate style avatar for user Teo
    I don't know what to define maxDir as. Can someone tell me what to do and why to do it?
    (5 votes)
    Default Khan Academy avatar avatar for user
  • piceratops ultimate style avatar for user Trevor Coleman
    In the challenge Mouse Stalker, I am on Step 2 and, for some reason, I cannot continue. It says that "mouse is undefined", however it use the method after where it is defined. My code looks like this:

    var Mover = function() {
    this.position = new PVector(width/2, height/2);
    this.velocity = new PVector(0, 0);
    this.acceleration = new PVector(0, 0);
    };

    Mover.prototype.update = function() {
    var mouse = new PVector(mouseX, mouseY);
    var dir = PVector.sub(mouse, this.position);
    dir.normalize();
    dir.mult(0.5);

    this.acceleration = dir;
    this.velocity.add(this.acceleration);
    this.velocity.limit(5);
    this.position.add(this.velocity);
    };

    Mover.prototype.display = function() {
    stroke(0);
    strokeWeight(2);
    fill(127);
    ellipse(this.position.x, this.position.y, 48, 48);
    };

    var maxDir = PVector.sub(new PVector(0, 0), new PVector (width - 1, height - 1));
    var maxMag = maxDir.mag ();
    var dir = PVector.sub(mouse, this.position);
    var closeness = ((maxMag - dir.mag()) / maxMag);

    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;
    }
    };

    var mover = new Mover();

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

    mover.update();
    mover.checkEdges();
    mover.display();
    };


    Please help me out!
    (3 votes)
    Default Khan Academy avatar avatar for user
  • leaf orange style avatar for user Bryce
    In the next Challenge, what is .mag()?
    (5 votes)
    Default Khan Academy avatar avatar for user
    • leaf grey style avatar for user Gregory G
      It's the magnitude of the vector. Like every vector has a magnitude and a direction. Think of the direction as an angle, and the magnitude as the third side of a triangle. The vector's first parameter would be the first side, and the vector's second parameter would be the second side. Obvious a^2 + b^2 = c^2 so you square both components of the vector, add them, then take the square root of that to find the magnitude.
      (8 votes)
  • duskpin ultimate style avatar for user Rachael Saxby
    I was on step 2 of the Mouse Stalker challenge. For some reason, it wouldn't accept this code as correct:

    Mover.prototype.update = function() {
    var mouse = new PVector(mouseX, mouseY);
    var dir = PVector.sub(mouse, this.position);
    var dirMag = dir.mag();
    var maxDir = new PVector(width, height);
    var maxMag = maxDir.mag();
    var closeness = (maxMag-dirMag)/maxMag;

    But, when I commented out my variable (dirMag), and just typed dir.mag() in the variable closeness, it was accepted.
    var closeness = (maxMag-dir.mag())/maxMag;

    Why is this?
    (4 votes)
    Default Khan Academy avatar avatar for user
  • winston default style avatar for user Darth Winston
    With help, I managed to finish the "Mouse Stalker" challenge. However, I'm having trouble understanding how the math works to make the Mover go faster with more closeness to the mouse cursor.
    (2 votes)
    Default Khan Academy avatar avatar for user
  • blobby green style avatar for user michael williams
    in my creature im trying to get rid of the dragging effect of the color an outline and nothing is working. can anyone point me in the right direction? i feel it has to do with the update.. but i have tried things like noStroke and such and it just turns it into a blob with no lines and still drags the color along.

    var Walker = function() {

    this.position = new PVector(random(width), random(height));
    this.velocity = new PVector(random(-2, 5), random(-2, 8));

    };

    Walker.prototype.Display = function() {

    stroke(0);
    strokeWeight(1);
    fill(14, 232, 203);
    ellipse(this.position.x,this.position.y,200,75);
    ellipse(this.position.x -45, (this.position.y) - 15, 40, 25);
    };



    Walker.prototype.CheckEdges = function() {
    if(this.position.x > width ) {
    this.position.x = 0;
    } else if (this.position.x < 0) {
    this.position.x = width;
    }else if (this.position.y > height) {
    this.position.y = 0;
    }else if(this.position.y < 0) {
    this.position.y = height;
    }

    };
    Walker.prototype.update = function() {
    this.position.add(this.velocity);
    };

    var c = new Walker();

    draw = function() {
    c.update();
    c.CheckEdges();
    c.Display();



    };
    (2 votes)
    Default Khan Academy avatar avatar for user
    • aqualine ultimate style avatar for user Sara
      If you put the background command inside the draw function, then it won't drag the color around anymore. By the way, I tried your code on a blank program, and it works really well if you put that background command in there. Just don't do noStroke(); because you're right, it really just does become a useless blob.
      -SavageMemer XD
      (1 vote)