Main content

### Course: Computer programming - JavaScript and the web > Unit 5

Lesson 6: Angular Movement- Angles and units
- Challenge: Spinning baton
- Angular velocity
- Challenge: Falling boulder
- Trigonometry
- Trigonometric ratios in right triangles
- Pointing towards movement
- Challenge: Turning car
- Polar coordinates
- Challenge: Spiral drawer
- Project: Asteroids spaceship

© 2024 Khan AcademyTerms of usePrivacy PolicyCookie Notice

# 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?

- 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)- Igor, consider: for two vectors A and B, (A - B) and (B - A) have identical magnitude but opposite direction.

If you want a concrete example, let A = (2, 5) and B = (6, -1).

A - B = (2-6, 5-(-1)) = (-4, 6)

B - A = (6-2, -1-5) = (4, -6) = (-1)*(-4,6)(11 votes)

- What is the purpose of having two draw functions in the code?(7 votes)
- Good catch.

There's no purpose at all in this case.

The second assignment overrides and destroys the first one.

So they could have just removed the first one.(7 votes)

- 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)- 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)

- how did they make a gradient on the boulder in the next challenge?(2 votes)
- In the
`Boulder.prototype.drawShape`

function, the function`lerpColor()`

is used. Look in the documentation for instructions on how to use this function.(5 votes)

- What is a pendulum and what is a algorithm?(2 votes)
- 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)

- 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)- They might prefer
`this.acceleration.mag()`

to`this.acceleration.x`

Since in (almost) all computer graphics, the Y axis grows downward, consistency demands that positive rotation must be clockwise. https://www.khanacademy.org/computer-programming/x-y-axes-study/5418062157201408(4 votes)

- 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)- 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)

- 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)`this.acceleration.mag`

is function. I suggest that you invoke it.(2 votes)

- I forgot what ------this.acceleration.mult(0);-------this does. Can someone tell me?(2 votes)
- It multiplies your acceleration vector by 0. It's the same as:
`this.acceleraction.x = this.acceleraction.x * 0;`

this.acceleraction.y = this.acceleraction.y * 0;

this.acceleraction.z = this.acceleraction.z * 0;(2 votes)

- I am facing problem in first step,

what to add in bracket

boulder.applyForce();(2 votes)