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

Angular velocity

Remember all this stuff?
location = location + velocity
velocity = velocity + acceleration
The stuff we dedicated almost all of the last two sections to? Well, we can apply exactly the same logic to a rotating object.
angle = angle + angular velocity
angular velocity = angular velocity + angular acceleration
In fact, the above is actually simpler than what we started with because an angle is a scalar quantity—a single number, not a vector!
Using the answer from the previous challenge, let’s say we wanted to rotate a baton in ProcessingJS by some angle. We would have code something like:
translate(width/2, height/2);
rotate(angle);
line(-50, 0, 50, 0);
ellipse(50, 0, 8, 8);
ellipse(-50, 0, 8, 8);
After we add in our principles of motion, we have the program below. The baton starts onscreen with no rotation and then spins faster and faster as the angle of rotation accelerates:
This idea can be incorporated into our Mover object. For example, we can add the properties related to angular motion to our Mover constructor.
var Mover = function(m, x, y) {
    this.position = new PVector(x, y);
    this.mass = m;

    this.angle = 0;
    this.aVelocity = 0;
    this.aAcceleration = 0;

    this.velocity = new PVector(random(-1, 1), random(-1, 1));
    this.acceleration = new PVector(0, 0);
};
And then in update(), we update both the position and angle according to the same algorithm!
Mover.prototype.update = function () {

    this.velocity.add(this.acceleration);
    this.position.add(this.velocity);

    this.aVelocity += this.aAcceleration;
    this.angle += this.aVelocity;

    this.acceleration.mult(0);
};
Of course, for any of this to matter, we also would need to rotate the object when displaying it.
Mover.prototype.display = function () {
    stroke(0, 0, 0);
    fill(175, 175, 175, 200);
    rectMode(CENTER);

    // pushMatrix and popMatrix are needed so that the shape rotation
    //  doesn't affect the rest of the world
    pushMatrix();
    // Set the origin at the shape's location
    translate(this.location.x, this.location.y);
    // Rotate by the angle
    rotate(this.angle);
    rect(0, 0, this.mass*16, this.mass*16);
    popMatrix();
};
Now, if we were to actually go ahead and run the above code, we wouldn’t see anything new. This is because the angular acceleration (this.aAcceleration = 0;) is initialized to zero. For the object to rotate, we need to give it an acceleration! Certainly, we could hard-code in a different number:
this.aAcceleration = 0.01;
Here's what a program looks like with the above logic, with a force calculated based on a central attractor:
That's a good start, but we can produce a more interesting result by dynamically assigning an angular acceleration according to forces in the environment - since objects don't usually spin of their own accord! Now, we could head pretty far down this road, trying to model the physics of angular acceleration using the concepts of torque and moment of inertia. That level of simulation is beyond the scope of this course - but we'll still get a bit more complex.
For now, a quick and dirty solution will do. We can produce reasonable results by simply calculating angular acceleration as a function of the object’s acceleration vector. Here’s one such example:
this.aAcceleration = this.acceleration.x;
Yes, this is completely arbitrary. But it does do something. If the object is accelerating to the right, its angular rotation accelerates in a clockwise direction; acceleration to the left results in a counterclockwise rotation. Of course, it’s important to think about scale in this case. The x component of the acceleration vector might be a quantity that’s too large, causing the object to spin in a way that looks ridiculous or unrealistic. So dividing the x component by some value, or perhaps constraining the angular velocity to a reasonable range, could really help. Here’s the entire update() method with these tweaks added.
Mover.prototype.update = function () {
    this.velocity.add(this.acceleration);
    this.position.add(this.velocity);

    // Calculate angular acceleration based on horizontal acceleration,
    //  and divide so it's not as strong
    this.aAcceleration = this.acceleration.x / 10.0;
    this.aVelocity += this.aAcceleration;

    // Use constrain to ensure velocity doesn't spin out of control
    this.aVelocity = constrain(this.aVelocity, -0.1, 0.1);
    this.angle += this.aVelocity;

    this.acceleration.mult(0);
};
Here's what the program looks like, with those changes incorporated:

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?

  • orange juice squid orange style avatar for user Igor Vínicius
    wow! someone ever notice that on the calculate attraction there is :
    var force = PVector.sub(this.position, m.position);

    but only by inverting and writing :

    var force = PVector.sub( m.position, this.position);

    it will simulate repulsion!
    (8 votes)
    Default Khan Academy avatar avatar for user
  • winston baby style avatar for user redmermaid2006
    What is the purpose of having two draw functions in the code?
    (7 votes)
    Default Khan Academy avatar avatar for user
  • spunky sam green style avatar for user Ethan Hudson
    in the challenge Falling boulder I have done what they ask of me, but it will not finish the challenge my code is this: angleMode = "radians";

    var Boulder = function(m, x, y) {
    this.position = new PVector(x, y);
    this.mass = m;
    this.width = this.mass * 10;
    this.angle = 0;
    this.aVelocity = 0;
    this.aAcceleration = 0;

    this.velocity = new PVector(0, 0);
    this.acceleration = new PVector(0, 0);
    };

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

    Boulder.prototype.update = function () {

    this.velocity.add(this.acceleration);
    this.position.add(this.velocity);

    this.aAcceleration = this.acceleration.x/22;
    this.aVelocity += this.aAcceleration.x;
    this.aVelocity = constrain(this.aVelocity, -0.1, 0.1);
    this.angle += this.aVelocity;


    this.acceleration.mult(0);
    };

    Boulder.prototype.display = function () {
    pushMatrix();
    translate(this.position.x, this.position.y);
    image(getImage("creatures/Hopper-Jumping"), this.width*0.25, this.width*0.3, 45, 55);
    rotate(this.angle);
    this.drawShape();
    popMatrix();
    };

    Boulder.prototype.drawShape = function() {
    ellipseMode(CENTER);
    fill(82, 82, 82);
    ellipse(0, 0, this.width, this.width);
    noStroke();
    var from = color(102, 102, 102, 40);
    var to = color(148, 148, 148, 40);
    var gradientBars = 20;
    for (var i = 0; i < gradientBars; i++) {
    var interA = lerpColor(from, to, i*1/gradientBars);
    var sWidth = (gradientBars-i)*this.width/gradientBars;
    fill(interA);
    ellipse(i, 0, sWidth, sWidth);
    }
    var from = color(102, 102, 102, 40);
    var to = color(94, 94, 94, 40);
    var gradientBars = 20;
    for (var i = 0; i < gradientBars; i++) {
    var interA = lerpColor(from, to, i*1/gradientBars);
    var sWidth = (gradientBars-i)*this.width/gradientBars;
    fill(interA);
    ellipse(-i, 0, sWidth, sWidth);
    }
    };

    var boulder = new Boulder(6, 10, 10);

    draw = function() {
    background(215, 245, 245);

    // draw mountain
    fill(181, 181, 181);
    stroke(150, 150, 150);
    triangle(0, 40, width-40, height, 0, height);

    // draw boulder
    var gravity = new PVector(0.1, 0.1);
    if (mouseIsPressed){
    gravity = new PVector(-0.6, -0.6);
    }
    boulder.applyForce(gravity);

    boulder.update();
    boulder.display();
    };


    If some one could help I would very much appreciate it
    (7 votes)
    Default Khan Academy avatar avatar for user
    • starky ultimate style avatar for user Evan Li
      I hope this isn't too late, but your code is almost there. Starting from //draw boulder:

      var gravity = new PVector(0.3, 0.3);
      var antigravity = new PVector(-0.5, -0.5);
      boulder.applyForce(gravity);
      if (mouseIsPressed) {
      boulder.applyForce(antigravity);
      }
      boulder.update()(;
      boulder.display();

      The reason you need the extra variable instead of simply changing "gravity" is because when the mouse is clicked, you still want regular gravity to be applied, but you are applying a force larger than gravity at the same time, which is why it can go upwards. I hope this helps!
      (4 votes)
  • duskpin ultimate style avatar for user zoesterosh
    how did they make a gradient on the boulder in the next challenge?
    (2 votes)
    Default Khan Academy avatar avatar for user
  • starky ultimate style avatar for user wiggybaby
    What is a pendulum and what is a algorithm?
    (2 votes)
    Default Khan Academy avatar avatar for user
    • leaf red style avatar for user Cavan P
      A pendulum is defined as a weight hung from a fixed point so that it can swing freely backward and forward, especially a rod with a weight at the end that regulates the mechanism of a clock. Pendulums are used in more than just clocks, however.

      The definition of 'algorithm' is a process or set of rules to be followed in calculations or other problem-solving operations, especially by a computer, however computers are not the only things which use algorithms.
      (4 votes)
  • mr pants teal style avatar for user Reed Fagan
    As a teacher of intro engineering (high school) I dabble in "moments". The dabbling has left me with the impression that positive (+) rotation is counterclockwise and negative (-) rotation is clockwise.

    In the next activity it makes me wonder if that is not true in Javascript because what I believe to be the relevant code is all "positive" yet the boulder rotates clockwise. I'll paste that code below.

    Can someone stop my head from spinning? :D

    this.aAcceleration = this.acceleration.x/10.0;
    this.aVelocity += this.aAcceleration;
    this.aVelocity = constrain(this.aVelocity, -0.1 , 0.1);
    this.angle += this.aVelocity;
    (1 vote)
    Default Khan Academy avatar avatar for user
  • piceratops ultimate style avatar for user Kid
    Guys on the last part of the challenge i don't know what i did wrong can you help?
    thanks.

    var Boulder = function(m, x, y) {
    this.position = new PVector(x, y);
    this.mass = m;
    this.width = this.mass * 10;
    this.angle = 0;
    this.aVelocity = 0;
    this.aAcceleration = 0;

    this.velocity = new PVector(0, 0);
    this.acceleration = new PVector(0, 0);
    };

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

    Boulder.prototype.update = function () {

    this.velocity.add(this.acceleration);
    this.position.add(this.velocity);

    this.aAcceleration = this.acceleration.x/22;
    this.aVelocity += this.aAcceleration.x;
    this.aVelocity = constrain(this.aVelocity, -0.1, 0.1);
    this.angle += this.aVelocity;


    this.acceleration.mult(0);
    };

    Boulder.prototype.display = function () {
    pushMatrix();
    translate(this.position.x, this.position.y);
    image(getImage("creatures/Hopper-Jumping"), this.width*0.25, this.width*0.3, 45, 55);
    rotate(this.angle);
    this.drawShape();
    popMatrix();
    };

    Boulder.prototype.drawShape = function() {
    ellipseMode(CENTER);
    fill(82, 82, 82);
    ellipse(0, 0, this.width, this.width);
    noStroke();
    var from = color(102, 102, 102, 40);
    var to = color(148, 148, 148, 40);
    var gradientBars = 20;
    for (var i = 0; i < gradientBars; i++) {
    var interA = lerpColor(from, to, i*1/gradientBars);
    var sWidth = (gradientBars-i)*this.width/gradientBars;
    fill(interA);
    ellipse(i, 0, sWidth, sWidth);
    }
    var from = color(102, 102, 102, 40);
    var to = color(94, 94, 94, 40);
    var gradientBars = 20;
    for (var i = 0; i < gradientBars; i++) {
    var interA = lerpColor(from, to, i*1/gradientBars);
    var sWidth = (gradientBars-i)*this.width/gradientBars;
    fill(interA);
    ellipse(-i, 0, sWidth, sWidth);
    }
    };

    var boulder = new Boulder(6, 10, 10);

    draw = function() {
    background(215, 245, 245);

    // draw mountain
    fill(181, 181, 181);
    stroke(150, 150, 150);
    triangle(0, 40, width-40, height, 0, height);

    // draw boulder
    var gravity = new PVector(0.1, 0.1);
    if (mouseIsPressed){
    boulder.applyForce(new PVector(-0.6, -0.6)).
    }
    boulder.applyForce(gravity);

    boulder.update();
    boulder.display();
    };
    (2 votes)
    Default Khan Academy avatar avatar for user
    • winston baby style avatar for user redmermaid2006
      If you haven't figured this out yet, turn this command into a variable: (new PVector(-0.6, -0.6)). Here is what I did:
      draw = function() {
      background(215, 245, 245);

      // draw mountain
      fill(181, 181, 181);
      stroke(150, 150, 150);
      triangle(0, 40, width-40, height, 0, height);

      // draw boulder

      var gravity = new PVector(0.1,0.1);
      var beaver= new PVector(-1,-1);
      if (mouseIsPressed){
      boulder.applyForce(beaver);
      }
      boulder.applyForce(gravity);
      boulder.update();
      boulder.display();
      };
      (2 votes)
  • aqualine ultimate style avatar for user Lize Brand
    Hi, I am having a little bit of trouble with the challenge.
    Boulder.prototype.update = function () {
    this.velocity.add(this.acceleration);
    this.position.add(this.velocity);

    this.aAcceleration = this.acceleration.mag;
    this.aVelocity += this.aAcceleration;
    this.aVelocity = constrain(this.aVelocity, -0.1, 0.1);
    this.angle += this.aVelocity;

    this.acceleration.mult(0);

    };

    I think I am supposed to change this.aAcceleration = this.acceleration.mag;
    into
    this.aAcceleration = this.acceleration.x;
    I don't understand why mag wouldn't work, though. Can someone please explain?
    (2 votes)
    Default Khan Academy avatar avatar for user
  • leaf green style avatar for user ☣The Reckoning☣(OFFLINE)
    I forgot what ------this.acceleration.mult(0);-------this does. Can someone tell me?
    (2 votes)
    Default Khan Academy avatar avatar for user
  • piceratops ultimate style avatar for user Kunal Sharma
    I am facing problem in first step,
    what to add in bracket
    boulder.applyForce();
    (2 votes)
    Default Khan Academy avatar avatar for user