Angular Movement

Let’s go all the way back to one of our first examples, the one where a Mover object accelerates towards the mouse.

You might notice that almost all of the shapes we’ve been drawing so far are circles. This is convenient for a number of reasons, one of which is that we don’t have to consider the question of rotation. Rotate a circle and, well, it looks exactly the same. However, there comes a time in all motion programmers’ lives when they want to draw something on the screen that points in the direction of movement. Perhaps you are drawing an ant, or a car, or a spaceship. And when we say "point in the direction of movement," what we are really saying is “rotate according to the velocity vector.” Velocity is a vector, with an x and a y component, but to rotate in ProcessingJS we need an angle. Let’s draw our trigonometry diagram one more time, with an object’s velocity vector:

OK. We know that the definition of tangent is:

tangent(angle)=\frac{velocity_y}{velocity_x}

The problem with the above is that we know velocity, but we don’t know the angle. We have to solve for the angle. This is where a special function known as inverse tangent comes in, sometimes referred to as arctangent or tan-1. (There is also an inverse sine and an inverse cosine.)

If the tangent of some value a equals some value b, then the inverse tangent of b equals a. For example:

 if tangent(a) = b then a = arctangent(b)

See how that is the inverse? The above now allows us to solve for the angle:

 if tangent(angle) = velocity_y / velocity_x then angle = arctangent(velocity_y / velocity_x)

Now that we have the formula, let’s see where it should go in our mover’s display() function. Notice that in ProcessingJS, the function for arctangent is called atan(). JavaScript also provides Math.atan() natively (as well as all the basic trig functions), but we'll stick with the ProcessingJS provided functions.

Mover.prototype.display = function () {
var angle = atan(this.velocity.y / this.velocity.x);

stroke(0, 0, 0);
fill(127, 127, 127);
pushMatrix();
rectMode(CENTER);
translate(this.position.x, this.position.y);
rotate(angle);
rect(0, 0, 30, 10);
popMatrix();
};

Now the above code is pretty darn close, and almost works. We still have a big problem, though. Let’s consider the two velocity vectors depicted below.

Though superficially similar, the two vectors point in quite different directions—opposite directions, in fact! However, if we were to apply our formula to solve for the angle to each vector…

V1 ⇒ angle = atan(-4/3) = atan(-1.25) = -0.9272952 radians = -53 degrees
V2 ⇒ angle = atan(4/-3) = atan(-1.25) = -0.9272952 radians = -53 degrees

…we get the same angle for each vector. This can’t be right for both; the vectors point in opposite directions! The thing is, this is a pretty common problem in computer graphics. Rather than simply using atan() along with a bunch of conditional statements to account for positive/negative scenarios, ProcessingJS (along with JavaScript and pretty much all programming environments) has a nice function called atan2() that does it for you.

Mover.prototype.display = function () {
var angle = atan2(this.velocity.y, this.velocity.x);

stroke(0, 0, 0);
fill(127, 127, 127);
pushMatrix();
rectMode(CENTER);
translate(this.position.x, this.position.y);
rotate(angle);
rect(0, 0, 30, 10);
popMatrix();
};

To simplify this even further, the PVector object itself provides a function called heading(), which takes care of calling atan2() for you so you can get the 2D direction angle, in radians, for any PVector.

Here's what the program looks like, all together. Move your mouse over it and see how it rotates!

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.