noc-book-2/content/01_vectors.html
2023-08-11 21:34:04 +00:00

984 lines
No EOL
72 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<section data-type="chapter">
<h1 id="chapter-1-vectors">Chapter 1. Vectors</h1>
<p>This book is all about looking at the world around us and developing ways to simulate it with code. In this first part of the book, Ill start by looking at basic physics: how an apple falls from a tree, how a pendulum swings in the air, how Earth revolves around the sun, and so on. Absolutely everything contained within the books first five chapters requires the use of the most basic building block for programming motion, the <strong>vector</strong>. And so thats where Ill begin the story.</p>
<p>The word <em>vector</em> can mean a lot of different things. Its the name of a New Wave rock band formed in Sacramento, California, in the early 1980s, and the name of a breakfast cereal manufactured by Kelloggs Canada. In the field of epidemiology, a vector is an organism that transmits infection from one host to another. In the C++ programming language, a vector (<code>std::vector</code>) is an implementation of a dynamically resizable array data structure.</p>
<p>While all these definitions are worth exploring, theyre not the focus here. Instead, this chapter dives into the <strong>Euclidean vector</strong> (named for the Greek mathematician Euclid), also known as the <strong>geometric vector</strong>. When you see the term vector in this book, you can assume it refers to a Euclidean vector, defined as an entity that has both magnitude and direction.</p>
<figure class="half-width-left">
<img src="images/01_vectors/01_vectors_1.png" alt=" Figure 1.1: A vector represented as an arrow drawn from point A to point B.">
<figcaption>Figure 1.1: A vector represented as an arrow drawn from point A to point B.</figcaption>
</figure>
<p>A vector is typically drawn as an arrow, as in Figure 1.1. The vectors direction is indicated by where the arrow is pointing, and its magnitude by the length of the arrow itself.</p>
<p>The vector in Figure 1.1 is drawn as an arrow from point A to point B. It serves as an instruction for how to travel from A to B.</p>
<h2 id="the-point-of-vectors">The Point of Vectors</h2>
<p>Before diving into more of the details about vectors, Id like to create a p5.js example that demonstrates why you should care about vectors in the first place. If youve watched any beginner p5.js tutorials, read any introductory p5.js textbooks, or taken an introduction to creative coding course (and hopefully youve done one of these things to help prepare you for this book!), you probably, at one point or another, learned how to write a bouncing ball sketch.</p>
<div data-type="example">
<h3 id="example-11-bouncing-ball-with-no-vectors">Example 1.1: Bouncing Ball with No Vectors</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/oadKdOndU" data-example-path="examples/01_vectors/example_1_1_bouncing_ball_with_no_vectors"><img src="examples/01_vectors/example_1_1_bouncing_ball_with_no_vectors/screenshot.png"></div>
<figcaption>If youre reading this book as a PDF or in print, this is the first example where the screenshot includes a trail to give a sense of the motion in the sketch. For more about how to draw trails, see the code examples linked from the website.</figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">// Variables for position and speed of ball.
let x = 100;
let y = 100;
let xspeed = 2.5;
let yspeed = 2;
function setup() {
createCanvas(640, 240);
background(255);
}
function draw() {
background(255);
// Move the ball according to its speed.
x = x + xspeed;
y = y + yspeed;
//{!6} Check for bouncing.
if (x > width || x &#x3C; 0) {
xspeed = xspeed * -1;
}
if (y > height || y &#x3C; 0) {
yspeed = yspeed * -1;
}
stroke(0);
fill(127);
//{!1} Draw the ball at the position (x,y).
circle(x, y, 48);
}</pre>
<p>In this example, theres a flat, two-dimensional world—a blank canvas—with a circular shape (a “ball”) traveling around. This ball has properties like position and speed that are represented in the code as variables.</p>
<table>
<thead>
<tr>
<th>Property</th>
<th>Variable Names</th>
</tr>
</thead>
<tbody>
<tr>
<td>position</td>
<td><code>x</code> and <code>y</code></td>
</tr>
<tr>
<td>speed</td>
<td><code>xspeed</code> and <code>yspeed</code></td>
</tr>
</tbody>
</table>
<p>In a more sophisticated sketch, you might have many more variables representing other properties of the ball and its environment:</p>
<table>
<thead>
<tr>
<th>Property</th>
<th>Variable Names</th>
</tr>
</thead>
<tbody>
<tr>
<td>acceleration</td>
<td><code>xacceleration</code> and <code>yacceleration</code></td>
</tr>
<tr>
<td>target position</td>
<td><code>xtarget</code> and <code>ytarget</code></td>
</tr>
<tr>
<td>wind</td>
<td><code>xwind</code> and <code>ywind</code></td>
</tr>
<tr>
<td>friction</td>
<td><code>xfriction</code> and <code>yfriction</code></td>
</tr>
</tbody>
</table>
<p>You might notice that for every concept in this world (wind, position, acceleration, and the like), there are two variables. And this is only a two-dimensional world. In a 3D world, youd need three variables for each property: <code>x</code>, <code>y</code>, and <code>z</code> for position, <code>xspeed</code>, <code>yspeed</code>, and <code>zspeed</code> for speed, and so on. Wouldnt it be nice to simplify the code to use fewer variables? Instead of starting the program with something like this:</p>
<pre class="codesplit" data-code-language="javascript">let x;
let y;
let xspeed;
let yspeed;</pre>
<p>Id love to start it with something like this:</p>
<pre class="codesplit" data-code-language="javascript">let position;
let speed;</pre>
<p>Thinking of the balls properties as vectors instead of a loose collection of separate values will allow me to do just that.</p>
<p>Taking this first step toward using vectors wont let you do anything new or magically turn a p5.js sketch into a full-on physics simulation. However, using vectors will help organize your code and provide a set of methods for common mathematical operations youll need over and over and over again while programming motion.</p>
<p>As an introduction to vectors, Im going to stick to two dimensions for quite some time (at least the first several chapters). All of these examples can be fairly easily extended to three dimensions (and the class Ill use, <code>p5.Vector</code>, allows for three dimensions). However, for the purposes of learning the fundamentals, the added complexity of the third dimension would be a distraction.</p>
<h2 id="vectors-in-p5js">Vectors in p5.js</h2>
<p>Think of a vector as the difference between two points, or as instructions for walking from one point to another. For example, Figure 1.2 shows some vectors and possible interpretations of them.</p>
<figure>
<img src="images/01_vectors/01_vectors_2.png" alt="Figure 1.2: Three example vectors drawn as arrows, with accompanying instructions for walking in north, south, east, or west directions">
<figcaption>Figure 1.2: Three example vectors drawn as arrows, with accompanying instructions for walking in north, south, east, or west directions</figcaption>
</figure>
<p>These vectors could be thought of in the following way:</p>
<table>
<thead>
<tr>
<th>Vector</th>
<th>Instructions</th>
</tr>
</thead>
<tbody>
<tr>
<td>(-15, 3)</td>
<td>Walk fifteen steps west; turn and walk three steps north.</td>
</tr>
<tr>
<td>(3, 4)</td>
<td>Walk three steps east; turn and walk four steps north.</td>
</tr>
<tr>
<td>(2, -1)</td>
<td>Walk two steps east; turn and walk one step south.</td>
</tr>
</tbody>
</table>
<p>Youve probably already thought this way when programming motion. For every frame of animation (a single cycle through p5s <code>draw()</code> loop), you instruct each object to reposition itself to a new spot a certain number of pixels away horizontally and a certain number of pixels away vertically. This instruction is essentially a vector, as in Figure 1.3; it has both magnitude (how far away did you travel?) and direction (which way did you go).</p>
<figure>
<img src="images/01_vectors/01_vectors_3.png" alt="Figure 1.3: A vector showing the number of horizontal and vertical steps to go from a position to a “new” position.">
<figcaption>Figure 1.3: A vector showing the number of horizontal and vertical steps to go from a position to a “new” position.</figcaption>
</figure>
<p>The vector sets the objects <strong><em>velocity</em></strong>, defined as the rate of change of the objects position. In other words, the velocity vector determines the objects new position for every frame of the animation, according to this basic algorithm for motion: <em>the new position is equal to the result of applying the velocity to the current position</em>.</p>
<p>If velocity is a vector (the difference between two points), what about position? Is it a vector too? Technically, you could argue that position is not a vector, since its not describing how to move from one point to another—its describing a single point in space. Nevertheless, another way to describe a position is as the path taken from the origin—point (0,0)—to the current point. When you think of position in this way, it becomes a vector, just like velocity, as in Figure 1.4.</p>
<figure>
<img src="images/01_vectors/01_vectors_4.png" alt="Figure 1.4: A computer graphics window with (0,0) in the top left, showing a position vector and a velocity vector">
<figcaption>Figure 1.4: A computer graphics window with (0,0) in the top left, showing a position vector and a velocity vector</figcaption>
</figure>
<p>In Figure 1.4, the vectors are placed on a computer graphics canvas. Unlike in Figure 1.2, the origin point (0,0) isnt the center, its the top-left corner. And instead of north, south, east, and west, there are positive and negative directions along the x- and y-axes (with y pointing down in the positive direction).</p>
<p>Lets examine the underlying data for both position and velocity. In the bouncing ball example, I originally had the following variables:</p>
<table>
<thead>
<tr>
<th>Property</th>
<th>Variable Names</th>
</tr>
</thead>
<tbody>
<tr>
<td>position</td>
<td><code>x</code>, <code>y</code></td>
</tr>
<tr>
<td>velocity</td>
<td><code>xspeed</code>, <code>yspeed</code></td>
</tr>
</tbody>
</table>
<p>Now Ill treat position and velocity as vectors instead, each represented by an object with <code>x</code> and <code>y</code> attributes. If I were to write a <code>Vector</code> class myself, Id start with something like this:</p>
<pre class="codesplit" data-code-language="javascript">class Vector {
constructor(x, y) {
this.x = x;
this.y = y;
}
}</pre>
<p>Notice how this class is designed to store the same data as before—two floating-point numbers per vector, an <code>x</code> value and a <code>y</code> value. At its core, a <code>Vector</code> object is just a convenient way to store two values (or three, as youll see in 3D examples) under one name.</p>
<p>As it happens, p5.js already has a built-in <code>p5.Vector</code> class, so I dont need to write one myself. And so this . . .</p>
<pre class="codesplit" data-code-language="javascript">let x = 100;
let y = 100;
let xspeed = 1;
let yspeed = 3.3;</pre>
<p>becomes . . .</p>
<pre class="codesplit" data-code-language="javascript">let position = createVector(100, 100);
let velocity = createVector(1, 3.3);</pre>
<p>Notice that the <code>position</code> and <code>velocity</code> vector objects arent created, as you might expect, by invoking a constructor function. Instead of writing <code>new p5.Vector(x, y)</code>, Ive called <code>createVector(x, y)</code>. The <code>createVector()</code> function is included in p5.js as a helper function to take care of details behind the scenes upon creation of the vector. Except in special circumstances, you should always create <code>p5.Vector</code> objects with <code>createVector()</code>. I should note that p5.js functions such as <code>createVector()</code> cant be executed outside of <code>setup()</code> or <code>draw()</code>, since the library wont yet be loaded. Ill demonstrate how to address this when I tackle the full bouncing ball example with vectors.</p>
<p>Now that there are two vector objects (<code>position</code> and <code>velocity</code>), Im ready to implement the vector-based algorithm for motion: <strong>position = position + velocity</strong>. In Example 1.1, without vectors, the code reads:</p>
<pre class="codesplit" data-code-language="javascript">// Add each speed to each position.
x = x + xspeed;
y = y + yspeed;</pre>
<p>In an ideal world, I would be able to rewrite this as:</p>
<pre class="codesplit" data-code-language="javascript">// Add the velocity vector to the position vector.
position = position + velocity;</pre><a data-type="indexterm" data-primary="addition operator"></a>
<p>In JavaScript, however, the addition operator <code>+</code> is reserved for primitive values (integers, floats, and the like). JavaScript doesnt know how to add two <code>p5.Vector</code> objects together any more than it knows how to add two <code>p5.Font</code> objects or <code>p5.Image</code> objects. Fortunately, the <code>p5.Vector</code> class includes methods for common mathematical operations.</p>
<h2 id="vector-addition">Vector Addition</h2>
<p>Before I continue looking at the <code>p5.Vector</code> class and the <code>add()</code> method, lets examine vector addition using the notation found in math and physics textbooks. Vectors are typically written either in boldface type or with an arrow on top. For the purposes of this book, to distinguish a <strong>vector</strong> (with magnitude and direction) from a <strong>scalar</strong> (a single value, such as an integer or a floating-point number), Ill use the arrow notation:</p>
<ul>
<li>Vector: <span data-type="equation">\vec{v}</span></li>
<li>Scalar: <span data-type="equation">{x}</span></li>
</ul>
<p>Lets say I have the two vectors shown in Figure 1.5.</p>
<figure>
<img src="images/01_vectors/01_vectors_5.png" alt="Figure 1.5: Two vectors
\vec{u} and \vec{v} depicted as triangles with components (5,2) and (3,4)">
<figcaption>Figure 1.5: Two vectors <span data-type="equation">\vec{u}</span> and <span data-type="equation">\vec{v}</span> depicted as triangles with components (5,2) and (3,4)</figcaption>
</figure>
<p>Each vector has two components, an <span data-type="equation">x</span> and a <span data-type="equation">y</span>. To add the two vectors together, add both <span data-type="equation">x</span> components and <span data-type="equation">y</span> components to create a new vector, as in Figure 1.6.</p>
<figure>
<img src="images/01_vectors/01_vectors_6.png" alt="Figure 1.6: Addition of vectors by adding the x and y components together.">
<figcaption>Figure 1.6: Addition of vectors by adding the x and y components together.</figcaption>
</figure>
<p>In other words, <span data-type="equation">\vec{w} = \vec{u} + \vec{v}</span> can be written as:</p>
<div data-type="equation">w_x = u_x + v_x</div>
<div data-type="equation">w_y = u_y + v_y</div>
<p>Then, replacing <span data-type="equation">\vec{u}</span> and <span data-type="equation">\vec{v}</span> with their values from Figure 1.6, you get:</p>
<div data-type="equation">w_x = 5 + 3 = 8</div>
<div data-type="equation">w_y = 2 + 4 = 6</div>
<p>Finally, write the result as a vector:</p>
<div data-type="equation">\vec{w} = (8,6)</div>
<div data-type="note">
<h3 id="addition-properties-with-vectors">Addition Properties with Vectors</h3>
<p>Addition with vectors follows the same algebraic rules as with real numbers.</p>
<p><em>The commutative rule:</em> <span data-type="equation">\vec{u} + \vec{v} = \vec{v} + \vec{u}</span></p>
<p><em>The associative rule:</em> <span data-type="equation">\vec{u} + (\vec{v} + \vec{w}) = (\vec{u} + \vec{v}) + \vec{w}</span></p>
<p>Fancy terminology and symbols aside, these rules boil down to quite a simple concept: the result is the same no matter the order in which the vectors are added. Replace the vectors with regular numbers (scalars) and these rules are easy to see:</p>
<div data-type="equation">3 + 2 = 2 + 3</div>
<div data-type="equation">(3 + 2) + 1 = 3 + (2 + 1)</div>
</div>
<p>Now that Ive covered the theory behind adding two vectors together, I can turn to adding vector objects in p5.js. Imagine again that Im creating my own <code>Vector</code> class. I could give it a function called <code>add()</code> that takes another <code>Vector</code> object as its argument:</p>
<pre class="codesplit" data-code-language="javascript">class Vector {
constructor(x, y) {
this.x = x;
this.y = y;
}
//{!4 .bold} New! A function to add another Vector to this Vector. Add the <em>x</em> components and the <em>y</em> components separately.
add(v) {
this.x = this.x + v.x;
this.y = this.y + v.y;
}
}</pre>
<p>The function looks up the <code>x</code> and <code>y</code> components of the two vectors and adds them separately. This is exactly how the built-in <code>p5.Vector</code> classs <code>add()</code> function is written, too. Knowing how it works, I can now return to the bouncing ball example with its <strong>position + velocity</strong> algorithm and implement vector addition:</p>
<pre class="codesplit" data-code-language="javascript">//{!1 .line-through} This does not work!
position = position + velocity;
//{!1} Add the velocity to the position.
position.add(velocity);</pre>
<p>Now we have what we need to rewrite the bouncing ball example with vectors.</p>
<div data-type="example">
<h3 id="example-12-bouncing-ball-with-vectors">Example 1.2: Bouncing Ball with Vectors!</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/qU5oPJijX" data-example-path="examples/01_vectors/example_1_2_bouncing_ball_with_vectors"><img src="examples/01_vectors/example_1_2_bouncing_ball_with_vectors/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">//{!2 .bold} Instead of a bunch of floats, we now just have two variables.
let position;
let velocity;
function setup() {
createCanvas(640, 240);
//{!2 .bold} Note how createVector() has to be called inside of setup().
position = createVector(100, 100);
velocity = createVector(2.5, 2);
}
function draw() {
background(255);
//{!1 .bold .no-comment}
position.add(velocity);
//{!6 .bold .code-wide} We still sometimes need to refer to the individual components of a p5.Vector and can do so using the dot syntax: position.x, velocity.y, etc.
if (position.x > width || position.x &#x3C; 0) {
velocity.x = velocity.x * -1;
}
if (position.y > height || position.y &#x3C; 0) {
velocity.y = velocity.y * -1;
}
stroke(0);
fill(127);
circle(position.x, position.y, 48);
}</pre>
<p>At this stage, you might feel somewhat disappointed. After all, these changes may appear to have made the code more complicated than the original version. While this is a perfectly reasonable and valid critique, its important to understand that the power of programming with vectors hasnt been fully realized just yet. Looking at a bouncing ball and only implementing vector addition is just the first step. As I move forward into a more complex world of multiple objects and multiple <strong><em>forces</em></strong> (which Ill introduce in Chapter 2) acting on those objects, the benefits of vectors will become more apparent.</p>
<p>I should, however, note an important aspect of the transition to programming with vectors. Even though Im using <code>p5.Vector</code> objects to encapsulate two values—the <code>x</code> and <code>y</code> of the balls position or the <code>x</code> and <code>y</code> of the balls velocity—under a single variable name, Ill still often need to refer to the <code>x</code> and <code>y</code> components of each vector individually.</p>
<p>The <code>circle()</code> function doesnt allow for a <code>p5.Vector</code> object as an argument. A circle can only be drawn with two scalar values, an x-coordinate and a y-coordinate. And so I must dig into the <code>p5.Vector</code> object and pull out the <code>x</code> and <code>y</code> components using object-oriented dot syntax:</p>
<pre class="codesplit" data-code-language="javascript">//{.line-through .no-comment}
circle(position, 48);
circle(position.x, position.y, 48);</pre>
<p>The same issue arises when testing if the circle has reached the edge of the window. In this case, I need to access the individual components of both vectors, <code>position</code> and <code>velocity</code>:</p>
<pre class="codesplit" data-code-language="javascript">if ((position.x > width) || (position.x &#x3C; 0)) {
velocity.x = velocity.x * -1;
}</pre>
<p>It may not always be obvious when to directly access an object's properties versus when to reference the object as a whole or use one of its methods. The goal of this chapter (and most of this book) is to help you distinguish between these scenarios by providing a variety of examples and use cases.</p>
<div data-type="exercise">
<h3 id="exercise-12">Exercise 1.2</h3>
<p>Take one of the walker examples from the Chapter 0 and convert it to use vectors.</p>
</div>
<div data-type="exercise">
<h3 id="exercise-11">Exercise 1.1</h3>
<p>Find something else youve previously made in p5.js using separate <code>x</code> and <code>y</code> variables, and use vectors instead.</p>
</div>
<div data-type="exercise">
<h3 id="exercise-13">Exercise 1.3</h3>
<p>Extend the bouncing ball with vectors example into 3D. Can you get a sphere to bounce around a box?</p>
</div>
<h2 id="more-vector-math">More Vector Math</h2>
<p>Addition was really just the first step. There are many mathematical operations commonly used with vectors. Heres a comprehensive table of the operations available as functions in the <code>p5.Vector</code> class.</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>Task</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>add()</code></td>
<td>Adds a vector to this vector</td>
</tr>
<tr>
<td><code>sub()</code></td>
<td>Subtracts a vector from this vector</td>
</tr>
<tr>
<td><code>mult()</code></td>
<td>Scale this vector with multiplication</td>
</tr>
<tr>
<td><code>div()</code></td>
<td>Scale this vector with division</td>
</tr>
<tr>
<td><code>mag()</code></td>
<td>Returns the magnitude of this vector</td>
</tr>
<tr>
<td><code>setMag()</code></td>
<td>Set the magnitude of this vector</td>
</tr>
<tr>
<td><code>normalize()</code></td>
<td>Normalize this vector to a unit length of 1</td>
</tr>
<tr>
<td><code>limit()</code></td>
<td>Limit the magnitude of this vector</td>
</tr>
<tr>
<td><code>heading()</code></td>
<td>Returns 2D heading of this vector expressed as an angle</td>
</tr>
<tr>
<td><code>rotate()</code></td>
<td>Rotate this 2D vector by an angle</td>
</tr>
<tr>
<td><code>lerp()</code></td>
<td>Linear interpolate to another vector</td>
</tr>
<tr>
<td><code>dist()</code></td>
<td>The Euclidean distance between two vectors (considered as points)</td>
</tr>
<tr>
<td><code>angleBetween()</code></td>
<td>Find the angle between two vectors</td>
</tr>
<tr>
<td><code>dot()</code></td>
<td>Returns the dot product of two vectors</td>
</tr>
<tr>
<td><code>cross()</code></td>
<td>Returns the cross product of two vectors (only relevant in three dimensions)</td>
</tr>
<tr>
<td><code>random2D()</code></td>
<td>Returns a random 2D vector</td>
</tr>
<tr>
<td><code>random3D()</code></td>
<td>Returns a random 3D vector</td>
</tr>
</tbody>
</table>
<p>Ill go through a few of the key functions now. As the examples get more sophisticated in later chapters, Ill continue to reveal the details of more of them.</p>
<h3 id="vector-subtraction">Vector Subtraction</h3>
<figure class="half-width-right">
<img src="images/01_vectors/01_vectors_7.png" alt="Figure 1.7: Showing the relationship between \vec{v} and -\vec{v} ">
<figcaption>Figure 1.7: Showing the relationship between <span data-type="equation">\vec{v}</span> and <span data-type="equation">-\vec{v}</span> </figcaption>
</figure>
<p>Having already covered addition, Ill now turn to subtraction. This ones not so bad; just take the plus sign and replace it with a minus! Before tackling subtraction itself, however, consider what it means for a vector <span data-type="equation">\vec{v}</span> to become <span data-type="equation">-\vec{v}</span>. The negative version of the scalar 3 is -3. A negative vector is similar: the polarity of each of the vectors components is inverted. So if <span data-type="equation">\vec{v}</span> has the components <span data-type="equation">(x, y)</span>, then <span data-type="equation">-\vec{v}</span> is <span data-type="equation">(-x, -y)</span>. Visually, this results in an arrow of the same length as the original vector pointing in the opposite direction, as depicted in Figure 1.7.</p>
<p>Subtraction, then, is the same as addition, only with the second vector in the equation treated as a negative version of itself:</p>
<div data-type="equation">\vec{u} - \vec{v} = \vec{u} + -\vec{v}</div>
<p>Just as vectors are added by placing them “tip to tail”—that is, aligning the tip (or end point) of one vector with the tail (or start point) of the next—vectors are subtracted by reversing the direction of the second vector and and placing it at the end of the first, as in Figure 1.8 .</p>
<figure>
<img src="images/01_vectors/01_vectors_8.png" alt="Figure 1.8 Showing vector subtraction as one vector placed at the end of another, but pointing in the opposite direction. ">
<figcaption>Figure 1.8 Showing vector subtraction as one vector placed at the end of another, but pointing in the opposite direction.</figcaption>
</figure>
<p>To actually solve the subtraction, take the difference of the vectors components. That is, <span data-type="equation">\vec{w} = \vec{u} - \vec{v}</span> can be written as:</p>
<div data-type="equation">w_x = u_x - v_x</div>
<div data-type="equation">w_y = u_y - v_y</div>
<p>Inside <code>p5.Vector</code>, the code reads:</p>
<pre class="codesplit" data-code-language="javascript">sub(v) {
this.x = this.x - v.x;
this.y = this.y - v.y;
}</pre>
<p>The following example demonstrates vector subtraction by taking the difference between two points (that are treated as vectors): the mouse position and the center of the window.</p>
<div data-type="example">
<h3 id="example-13-vector-subtraction">Example 1.3: Vector Subtraction</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/HtXiElQbC" data-example-path="examples/01_vectors/example_1_3_vector_subtraction"><img src="examples/01_vectors/example_1_3_vector_subtraction/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">function draw() {
background(255);
//{!2} Two vectors, one for the mouse location and one for the center of the window
let mouse = createVector(mouseX, mouseY);
let center = createVector(width / 2, height / 2);
//{!3} Draw the original two vectors
stroke(200);
strokeWeight(4);
line(0, 0, mouse.x, mouse.y);
line(0, 0, center.x, center.y);
// Vector subtraction!
mouse.sub(center);
//{!3} Draw a line to represent the result of subtraction.
// Notice how I move the origin with translate() to place the vector
stroke(0);
translate(width / 2, height / 2);
line(0, 0, mouse.x, mouse.y);
}</pre>
<p>Note the use of <code>translate()</code> to visualize the resulting vector as a line from the center <code>(width/2, height/2)</code> to the mouse. Vector subtraction is its own kind of translation, moving the “origin” of a position vector. Here, by subtracting the center vector from the mouse vector, Im effectively “moving” the starting point of resulting vector to the center of the canvas. Therefore I also need to move the origin using <code>translate()</code>. Without this, the line would be drawn from the top-left corner, and the visual connection wouldnt be as clear.</p>
<h3 id="vector-multiplication-and-division">Vector Multiplication and Division</h3>
<p>Moving on to multiplication, you have to think a bit differently. Multiplying a vector typically refers to the process of <strong>scaling</strong> a vector. If I want to scale a vector to twice its size or one-third of its size, while leaving its direction the same, I would say: “Multiply the vector by 2” or “Multiply the vector by 1/3.” Unlike with addition and subtraction, Im multiplying the vector by a scalar (a single number), not by another vector. Figure 1.9 illustrates how to scale a vector by a factor of 3.</p>
<figure class="half-width-right">
<img src="images/01_vectors/01_vectors_9.png" alt="Figure 1.9 Scaling a vector with multiplication">
<figcaption>Figure 1.9 Scaling a vector with multiplication</figcaption>
</figure>
<p>To scale a vector, multiply each component (<span data-type="equation">x</span> and <span data-type="equation">y</span>) by a scalar. That is, <span data-type="equation">\vec{w} = \vec{u} * n</span> can be written as:</p>
<div data-type="equation">w_x = u_x * n</div>
<div data-type="equation">w_y = u_y * n</div>
<p>As an example, say <span data-type="equation">\vec{u} = (-3, 7)</span> and <span data-type="equation">n = 3</span>. You can calculate <span data-type="equation">\vec{w} = \vec{u} * n</span>as follows:</p>
<div data-type="equation">w_x = -3 * 3</div>
<div data-type="equation">w_y = 7 * 3</div>
<div data-type="equation">\vec{w} = (-9,21)</div>
<p>This is exactly how the <code>mult()</code> function inside the <code>p5.Vector</code> class works.</p>
<pre class="codesplit" data-code-language="javascript">mult(n) {
//{!2} The components of the vector are multiplied by a number.
this.x = this.x * n;
this.y = this.y * n;
}</pre>
<p>Implementing multiplication in code is as simple as:</p>
<pre class="codesplit" data-code-language="javascript">let u = createVector(-3, 7);
// This p5.Vector is now three times the size and is equal to (-9, 21). (See Figure 1.9)
u.mult(3);</pre>
<p>Example 1.4 illustrates vector multiplication by drawing a line between the mouse and the center of the canvas, as in the previous example, and then scaling that line by 0.5.</p>
<div data-type="example">
<h3 id="example-14-multiplying-a-vector">Example 1.4: Multiplying a Vector</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/VQfwqpDlv" data-example-path="examples/01_vectors/example_1_4_vector_multiplication"><img src="examples/01_vectors/example_1_4_vector_multiplication/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">function draw() {
background(255);
let mouse = createVector(mouseX, mouseY);
let center = createVector(width / 2, height / 2);
mouse.sub(center);
translate(width / 2, height / 2);
strokeWeight(2);
stroke(200);
line(0, 0, mouse.x, mouse.y);
//{!1} Multiplying a vector! The vector is now half its original size (multiplied by 0.5).
mouse.mult(0.5);
stroke(0);
strokeWeight(4);
line(0, 0, mouse.x, mouse.y);
}</pre>
<p>The resulting vector is half its original size. Rather than multiplying the vector by 0.5, I could also achieve the same effect by dividing the vector by 2, as in Figure 1.10.</p>
<figure>
<img src="images/01_vectors/01_vectors_10.png" alt="Figure 1.10 Scaling a vector with division">
<figcaption>Figure 1.10 Scaling a vector with division</figcaption>
</figure>
<p>Vector division, then, works just like vector multiplication—just replace the multiplication sign (<code>*</code>) with the division sign (<code>/</code>). Heres how the <code>p5.Vector</code> class implements the <code>div()</code> function:</p>
<pre class="codesplit" data-code-language="javascript">div(n) {
this.x = this.x / n;
this.y = this.y / n;
}</pre>
<p>And heres how to use the <code>div()</code> function in a sketch:</p>
<pre class="codesplit" data-code-language="javascript">let u = createVector(8, -4);
// Dividing a vector! The vector is now half its original size (divided by 2).
u.div(2);</pre>
<p>This takes the vector <code>u</code> and divides it by 2.</p>
<div data-type="note">
<h3 id="more-number-properties-with-vectors">More Number Properties with Vectors</h3>
<p>As with addition, basic algebraic rules of multiplication apply to vectors.</p>
<p>The associative rule: <span data-type="equation">(n * m) * \vec{v} = n * (m * \vec{v})</span></p>
<p>The distributive rule with two scalars, one vector: <span data-type="equation">(n + m) * \vec{v} = (n * \vec{v}) + (m * \vec{v})</span></p>
<p>The distributive rule with two vectors, one scalar: <span data-type="equation">(\vec{u} + \vec{v}) * n = (\vec{u} * n) + (\vec{v} * n)</span></p>
</div>
<h2 id="vector-magnitude">Vector Magnitude</h2>
<figure class="half-width-right">
<img src="images/01_vectors/01_vectors_11.png" alt=" Figure 1.11: The length or “magnitude” of a vector \vec{v} is often written as: \lVert\vec{v}\rVert">
<figcaption>Figure 1.11: The length or “magnitude” of a vector <span data-type="equation">\vec{v}</span> is often written as: <span data-type="equation">\lVert\vec{v}\rVert</span></figcaption>
</figure>
<p>Multiplication and division, as just described, alter the length of a vector without affecting its direction. Perhaps youre wondering: “OK, so how do I know what the length of a vector is? I know the vectors components (<span data-type="equation">x</span> and <span data-type="equation">y</span>), but how long (in pixels) is the actual arrow?” Understanding how to calculate the length of a vector, also known as its <strong>magnitude</strong>, is incredibly useful and important.</p>
<figure class="half-width-right">
<img src="images/01_vectors/01_vectors_12.png" alt="Figure 1.12: The Pythagorean theorem calculates the length of a vector using its components.">
<figcaption>Figure 1.12: The Pythagorean theorem calculates the length of a vector using its components.</figcaption>
</figure>
<p>Notice in Figure 1.11 how the vector, drawn as an arrow and two components (<span data-type="equation">x</span> and <span data-type="equation">y</span>), creates a right triangle. The sides are the components, and the hypotenuse is the arrow itself. Were lucky to have this right triangle, because once upon a time, a Greek mathematician named Pythagoras discovered a lovely formula that describes the relationship between the sides and hypotenuse of a right triangle. This formula, the <strong>Pythagorean theorem</strong>, is <span data-type="equation">a^2 + b^2 = c^2</span>, or <em>a</em> squared plus <em>b</em> squared equals <em>c</em> squared (see Figure 1.12).</p>
<p>Armed with this formula, we can now compute the magnitude of <span data-type="equation">\vec{v}</span> as follows:</p>
<div data-type="equation">||\vec{v}||=\sqrt{v_x * v_x + v_y * v_y}</div>
<p>In the <code>p5.Vector</code> class, the <code>mag()</code> function is defined using the same formula:</p>
<pre class="codesplit" data-code-language="javascript">mag() {
return sqrt(this.x * this.x + this.y * this.y);
}</pre>
<p>Heres a sketch that calculates the magnitude of the vector between the mouse and the center of the canvas, and visualizes it as a rectangle drawn across the top of the window.</p>
<div data-type="example">
<h3 id="example-15-vector-magnitude">Example 1.5: Vector Magnitude</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/rld_CtioUU" data-example-path="examples/01_vectors/example_1_5_vector_magnitude"><img src="examples/01_vectors/example_1_5_vector_magnitude/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">function setup() {
createCanvas(640, 240);
}
function draw() {
background(255);
let mouse = createVector(mouseX, mouseY);
let center = createVector(width / 2, height / 2);
mouse.sub(center);
//{!3} The magnitude (i.e. length) of a vector can be accessed via the mag() function. Here it is used as the width of a rectangle drawn at the top of the window.
let m = mouse.mag();
fill(0);
rect(0, 0, m, 10);
translate(width / 2, height / 2);
line(0, 0, mouse.x, mouse.y);
}</pre>
<p>Notice how the magnitude (length) of a vector is always positive, even if the vectors components are negative.</p>
<h2 id="normalizing-vectors">Normalizing Vectors</h2>
<figure class="half-width-right">
<img src="images/01_vectors/01_vectors_13.png" alt="Figure 1.13 When a vector is normalized, it points in the same direction, but its been resized to a “unit” length of 1.">
<figcaption>Figure 1.13 When a vector is normalized, it points in the same direction, but its been resized to a “unit” length of 1.</figcaption>
</figure>
<p>Calculating the magnitude of a vector is only the beginning. It opens the door to many possibilities, the first of which is <strong>normalization</strong> (Figure 1.13). This is the process of making something “standard” or, well . . . “normal.” In the case of vectors, the convention is that a standard vector has a length of 1. To normalize a vector, therefore, is to take a vector of any length and change its length to 1, without changing its direction. That normalized vector is then called a <strong>unit vector</strong>.</p>
<p>A unit vector describes a vectors direction without regard to its length. Youll see this come in especially handy once I start to work with forces in Chapter 2.</p>
<p>For any given vector <span data-type="equation">\vec{u}</span> , its unit vector (written as <span data-type="equation">\hat{u}</span>) is calculated as follows:</p>
<div data-type="equation">\hat{u} = \frac{\vec{u}}{||\vec{u}||}</div>
<figure class="half-width-right">
<img src="images/01_vectors/01_vectors_14.png" alt="Figure 1.14 To normalize a vector, the components are divided by the magnitude of a vector.">
<figcaption>Figure 1.14 To normalize a vector, the components are divided by the magnitude of a vector.</figcaption>
</figure>
<p>In other words, to normalize a vector, divide each component by the vectors magnitude. To see why this works, consider a vector (4,3), which has a magnitude of 5 (see Figure 1.14). Once normalized, the vector will have a magnitude of 1. Thinking of the vector as a right triangle, normalization shrinks the hypotenuse down by dividing by 5 (since 5/5 = 1). In that process, each sides shrinks as well, also by a factor of 5. The side lengths go from 4 and 3 to 4/5 and 3/5.</p>
<p>In the <code>p5.Vector</code> class, the normalization method is written as follows:</p>
<pre class="codesplit" data-code-language="javascript">normalize() {
let m = this.mag();
this.div(m);
}</pre>
<p>Of course, theres one small issue. What if the magnitude of the vector is 0? You cant divide by 0! Some quick error checking fixes that right up:</p>
<pre class="codesplit" data-code-language="javascript">normalize() {
let m = this.mag();
if (m > 0) {
this.div(m);
}
}</pre>
<p>This sketch uses normalization to give the vector between the mouse and the center of the canvas a fixed length, regardless of the actual magnitude of the original vector.</p>
<div data-type="example">
<h3 id="example-16-normalizing-a-vector">Example 1.6: Normalizing a Vector</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/5dWkegAID" data-example-path="examples/01_vectors/example_1_6_vector_normalize"><img src="examples/01_vectors/example_1_6_vector_normalize/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">function draw() {
background(255);
let mouse = createVector(mouseX, mouseY);
let center = createVector(width / 2, height / 2);
mouse.sub(center);
translate(width / 2, height / 2);
stroke(200);
strokeWeight(2);
line(0, 0, mouse.x, mouse.y);
//{!2} In this example, after the vector is normalized, it is multiplied by 50. Note that no matter where the mouse is, the vector always has the same length (50) due to the normalization process.
mouse.normalize();
mouse.mult(50);
stroke(0);
strokeWeight(8);
line(0, 0, mouse.x, mouse.y);
}</pre>
<p>Notice how Ive multiplied the <code>mouse</code> vector by 50 after normalizing it to 1. Normalization is often the first step in creating a vector of a specific length, even if the desired length is something other than 1. Youll see more of this later in the chapter.</p>
<p>All this vector math stuff sounds like something you should know about, but why? How will it actually help you write code? Patience. Itll take some time before the awesomeness of using <code>p5.Vector</code> fully comes to light. This is a fairly common occurrence when learning a new data structure. For example, when you first learn about arrays, it might seem like more work to use an array than to have several variables stand for multiple things. That plan quickly breaks down when you need 100, 1,000, or 10,000 things, however.</p>
<p>The same can be true for vectors. What might seem like more work now will pay off later, and pay off quite nicely. And you dont have to wait too long, as your reward will come in the next chapter. For now, however, Ill focus on <em>how</em> it works, and on how working with vectors provides a different way to think about motion.</p>
<h2 id="motion-with-vectors">Motion with Vectors</h2>
<p>What does it mean to program motion using vectors? Youve gotten a taste of it in <a href="#example-12-bouncing-ball-with-vectors">Example 1.2</a>, the bouncing ball. The circle 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:</p>
<pre class="codesplit" data-code-language="javascript">position.add(velocity);</pre>
<p>Then the object is drawn at the new position:</p>
<pre class="codesplit" data-code-language="javascript">circle(position.x, position.y, 48);</pre>
<p>Together, these steps are Motion 101.</p>
<ol>
<li><strong>Add velocity to position</strong></li>
<li><strong>Draw object at position</strong></li>
</ol>
<p>In the bouncing ball example, all of this code happened within <code>setup()</code> and <code>draw()</code>. What I want to do now is move toward encapsulating all of the logic for an objects motion inside of a <strong><em>class</em></strong>. This way, I can create a foundation for programming moving objects that I can easily reuse again and again. (See <a href="/random#the-random-walker-class">"The Random Walker Class" in the Chapter 0</a> for a brief review of the basics of object-oriented-programming .)</p>
<p>To start, Im going to create a generic <code>Mover</code> class that will describe a shape moving around the canvas. For that, I must consider the following two questions:</p>
<ol>
<li><strong>What data does a mover have?</strong></li>
<li><strong>What functionality does a mover have?</strong></li>
</ol>
<p>The “Motion 101” algorithm answers both of these questions. First, a <code>Mover</code> object has two pieces of data, <code>position</code> and <code>velocity</code>, which are both <code>p5.Vector</code> objects. These are initialized in the objects constructor. In this case, Ill arbitrarily decide to initialize the <code>Mover</code> object by giving it a random position and velocity. Note the use of <code>this</code> with all variables that are part of the <code>Mover</code> object.</p>
<pre class="codesplit" data-code-language="javascript">class Mover {
constructor() {
this.position = createVector(random(width), random(height));
this.velocity = createVector(random(-2,2), random(-2, 2));
}</pre>
<p>The functionality follows suit. The <code>Mover</code> needs to move (by applying its velocity to its position) and it needs to be visible. Ill implement these needs as functions named <code>update()</code> and <code>show()</code>. Ill put all of the motion logic code in <code>update()</code> and draw the object in <code>show()</code>.</p>
<pre class="codesplit" data-code-language="javascript"> update() {
//{!1} The Mover moves.
this.position.add(this.velocity);
}
show() {
stroke(0);
fill(175);
//{!1} The Mover is drawn as a circle.
circle(this.position.x, this.position.y, 48);
}
}</pre>
<p>The <code>Mover</code> class also needs a function that determines what the object should do when it reaches the edge of the canvas. For now, Ill do something simple, and have it wrap around the edges.</p>
<pre class="codesplit" data-code-language="javascript"> checkEdges() {
//{!11} When it reaches one edge, set position to the other.
if (this.position.x > width) {
this.position.x = 0;
} else if (this.position.x &#x3C; 0) {
this.position.x = width;
}
if (this.position.y > height) {
this.position.y = 0;
} else if (this.position.y &#x3C; 0) {
this.position.y = height;
}
}</pre>
<p>Now the <code>Mover</code> class is finished, but the class itself isnt an object; its a template for creating an instance of an object. To actually create a <code>Mover</code> object, I first need to declare a variable to hold it:</p>
<pre class="codesplit" data-code-language="javascript">let mover;</pre>
<p>Then, inside the <code>setup()</code> function, I create the object by invoking the class name along with the <code>new</code> keyword. This triggers the classs constructor to make an instance of the object.</p>
<pre class="codesplit" data-code-language="javascript">mover = new Mover();</pre>
<p>Now all that remains is to call the appropriate functions in <code>draw()</code>:</p>
<pre class="codesplit" data-code-language="javascript">mover.update();
mover.checkEdges();
mover.show();</pre>
<p>Heres the entire example for reference:</p>
<div data-type="example">
<h3 id="example-17-motion-101-velocity">Example 1.7: Motion 101 (Velocity)</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/6foX0NUfS" data-example-path="examples/01_vectors/example_1_7_motion_101_velocity"><img src="examples/01_vectors/example_1_7_motion_101_velocity/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">//{!1} Declare Mover object.
let mover;
function setup() {
createCanvas(640, 240);
//{!1} Create Mover object.
mover = new Mover();
}
function draw() {
background(255);
//{!3} Call functions on Mover object.
mover.update();
mover.checkEdges();
mover.show();
}</pre>
<pre class="codesplit" data-code-language="javascript">class Mover {
constructor() {
//{!2} The object has two vectors: position and velocity.
this.position = createVector(random(width), random(height));
this.velocity = createVector(random(-2, 2), random(-2, 2));
}
update() {
//{!1} Motion 101: position changes by velocity.
this.position.add(this.velocity);
}
show() {
stroke(0);
strokeWeight(2);
fill(127);
circle(this.position.x, this.position.y, 48);
}
checkEdges() {
if (this.position.x > width) {
this.position.x = 0;
} else if (this.position.x &#x3C; 0) {
this.position.x = width;
}
if (this.position.y > height) {
this.position.y = 0;
} else if (this.position.y &#x3C; 0) {
this.position.y = height;
}
}
}</pre>
<p>If object-oriented programming is at all new to you, one aspect here may seem a bit strange. I spent the beginning of this chapter discussing the <code>p5.Vector</code> class, and this class is the template for making the <code>position</code> object and the <code>velocity</code> object. So what are those objects doing inside of yet another object, the <code>Mover</code> object?</p>
<p>In fact, this is just about the most normal thing ever. An object is something that holds data (and functionality). That data can be numbers, or it can be other objects (arrays too)! Youll see this over and over again in this book. In <a href="/particles#why-you-need-particle-systems">Chapter 4</a> , for example, Ill write a class to describe a system of particles. That <code>ParticleSystem</code> object will include a list of <code>Particle</code> objects . . . and each <code>Particle</code> object will have as its data several <code>p5.Vector</code> objects!</p>
<p>At this point, you hopefully feel comfortable with two things: (1) what a vector is, and (2) how to use vectors 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 are in order, however, you 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 sophisticated motion—the kind of motion that appears in the world around us—one more vector needs to be added to the class: <code>acceleration</code>.</p>
<h2 id="acceleration">Acceleration</h2>
<p><strong><em>Acceleration</em></strong> is <em>the </em>rate of change of velocity. Think about that definition for a moment. Is it a new concept? Not really. Earlier I defined velocity as<em> </em>the rate of change of position, so in essence Im developing a “trickle-down” effect. Acceleration affects velocity, which in turn affects position. (To provide some brief foreshadowing, this point will become even more crucial in the next chapter, when I look at how forces like friction affect acceleration, which affects velocity, which affects position.) In code, this trickle-down effect reads:</p>
<pre class="codesplit" data-code-language="javascript">velocity.add(acceleration);
position.add(velocity);</pre>
<p>As an exercise, from this point forward, Im going to make a rule for myself: Ill try to write every example in the rest of this book without ever touching the values of velocity and position (except to initialize them). In other words, the goal for programming motion is to come up with an algorithm for how to calculate acceleration, and then let the trickle-down effect work its magic. (In truth, there will be a multitude of reasons to break this rule, and break it I shall. Nevertheless, its a useful constraint to begin with to illustrate the principles behind the motion algorithm with acceleration.)</p>
<p>The next step, then, is to come up with a way to calculate acceleration. Here are a few possible algorithms:</p>
<ol>
<li><em>A constant acceleration</em></li>
<li><em>A random acceleration</em></li>
<li><em>Acceleration toward the mouse</em></li>
</ol>
<p>Ill use the rest of this chapter to show you how to implement these algorithms.</p>
<h3 id="acceleration-algorithm-1">Acceleration Algorithm #1</h3>
<p>Acceleration Algorithm #1, a constant acceleration, isnt particularly interesting, but its the simplest and thus an excellent starting point to incorporate acceleration into the code. The first thing to do is add another variable to the <code>Mover</code> class:</p>
<pre class="codesplit" data-code-language="javascript">class Mover {
constructor(){
//{!2} Initialize stationary mover at center of canvas
this.position = createVector(width / 2, height / 2);
this.velocity = createVector(0, 0);
//{!1 .bold} A new vector for acceleration
this.acceleration = createVector(0, 0);
}</pre>
<p>Next, incorporate acceleration into the <code>update()</code> function:</p>
<pre class="codesplit" data-code-language="javascript"> update() {
//{!2 .bold} The motion algorithm is now two lines of code!
this.velocity.add(this.acceleration);
this.position.add(this.velocity);
}</pre>
<p>I'm almost finished. The only missing piece is to get that mover moving! In the constructor, the initial velocity is set to zero, rather than a random vector as previously done. Therefore, when the sketch starts, the object is at rest. To get it moving instead of changing the velocity directly, I'll update it through the object's acceleration. According to Algorithm #1, the acceleration should be constant, so I'll choose a value now.</p>
<pre class="codesplit" data-code-language="javascript"> this.acceleration = createVector(-0.001, 0.01);</pre>
<p>This means that for every frame of the animation, the objects velocity should increase by -0.001 pixels in the x direction and 0.01 pixels in the y direction. Maybe youre thinking, “Gosh, those values seem awfully small!” Indeed, they are quite tiny. but thats by design. Acceleration values accumulate over time in the velocity, about 30 times per second depending on the sketchs frame rate. To keep the magnitude of the velocity vector from growing too quickly and spiraling out of control, the acceleration values should remain quite small.</p>
<p>I can also help keep the velocity within a reasonable range by incorporating the <code>p5.Vector</code> function <code>limit()</code>, which puts a cap on the magnitude of a vector.</p>
<pre class="codesplit" data-code-language="javascript">// The limit() function constrains the magnitude of a vector.
this.velocity.limit(10);</pre>
<p>This translates to the following:</p>
<p><em>What is the magnitude of </em><code><em>velocity</em></code><em>? If its less than 10, no worries; just leave it as is. If its more than 10, however, reduce it to 10!</em></p>
<div data-type="exercise">
<h3 id="exercise-14">Exercise 1.4</h3>
<p>Write the <code>limit()</code> function for the <code>p5.Vector</code> class.</p>
<pre class="codesplit" data-code-language="javascript"> limit(max) {
if (<span class="blank">this.mag() > mag</span>) {
<span class="blank">this.normalize()</span>;
<span class="blank">this.mult(max)</span>;
}
}</pre>
</div>
<p>Lets take a look at the changes to the <code>Mover</code> class, complete with <code>acceleration</code> and <code>limit()</code>.</p>
<div data-type="example">
<h3 id="example-18-motion-101-velocity-and-constant-acceleration">Example 1.8: Motion 101 (Velocity and Constant Acceleration)</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/4GSialOpQw" data-example-path="examples/01_vectors/example_1_8_motion_101_velocity_and_constant_acceleration"><img src="examples/01_vectors/example_1_8_motion_101_velocity_and_constant_acceleration/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">class Mover {
constructor() {
this.position = createVector(width / 2, height / 2);
this.velocity = createVector(0, 0);
// Acceleration is the key!
this.acceleration = createVector(-0.001, 0.01);
//{!1} The variable topspeed will limit the magnitude of velocity.
this.topSpeed = 10;
}
update() {
//{!2} Velocity changes by acceleration and is limited by topspeed.
this.velocity.add(this.acceleration);
this.velocity.limit(this.topSpeed);
this.position.add(this.velocity);
}
// show() is the same.
show() {}
//{!1} checkEdges() is the same.
checkEdges() {}
}</pre>
<p>The net result is that the object falls down and to the left, gradually getting faster and faster until it reaches the maximum velocity.</p>
<div data-type="exercise">
<h3 id="exercise-15">Exercise 1.5</h3>
<p>Create a simulation of an object (think about a vehicle?) that accelerates when you press the up key and brakes when you press the down key.</p>
</div>
<h3 id="acceleration-algorithm-2">Acceleration Algorithm #2</h3>
<p>Now on to Acceleration Algorithm #2, a random acceleration. In this case, instead of initializing <code>acceleration</code> in the objects constructor, I want to randomly set its value inside the <code>update()</code> function. This way the object will get a different acceleration vector for every frame of the animation.</p>
<pre class="codesplit" data-code-language="javascript">update() {
//{!1} The random2D() function returns a unit vector pointing in a random direction.
this.acceleration = p5.Vector.random2D();
this.velocity.add(this.acceleration);
this.velocity.limit(this.topspeed);
this.position.add(this.velocity);
}</pre>
<p>The random2D() function produces a normalized vector, meaning it has a random direction, but its magnitude is always 1. To make things interesting, I can try scaling the random vector by a constant value:</p>
<pre class="codesplit" data-code-language="javascript"> this.acceleration = p5.Vector.random2D();
//{.bold} Constant
this.acceleration.mult(0.5);</pre>
<p>Or, for even greater variety, I can scale the acceleration to a random value:</p>
<pre class="codesplit" data-code-language="javascript"> this.acceleration = p5.Vector.random2D();
//{.bold} Random
this.acceleration.mult(random(2));</pre>
<p>This way the <code>acceleration</code> vector will have a random direction and a random magnitude between 0 and 2.</p>
<div data-type="example">
<h3 id="example-19-motion-101-velocity-and-random-acceleration">Example 1.9: Motion 101 (Velocity and Random Acceleration)</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/w9DU8ccWMf" data-example-path="examples/01_vectors/example_1_9_motion_101_velocity_and_random_acceleration"><img src="examples/01_vectors/example_1_9_motion_101_velocity_and_random_acceleration/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<p>Its crucial to understand that acceleration doesnt merely refer to <em>speeding up</em> or <em>slowing down.</em> Rather, as this example has shown, it refers to <em>any change</em> in velocity—magnitude or direction. Acceleration is used to steer an object, and youll see this again and again in future chapters as I begin to code objects that make decisions about how to move.</p>
<p>You might also notice how this example is another kind of “random walker.”<strong><em> [CROSS REFERENCE]</em></strong>. A key distinction between what Im doing here and the previous chapters examples, however, lies in <em>what</em> is being randomized. With the traditional random walker, I was directly manipulating the velocity, meaning each step was completely independent of the last. In this example, its the acceleration (the rate of change of velocity) that's being randomized, not the velocity itself. This makes the object's motion dependent on its previous state: the velocity changes incrementally according to the random acceleration. The resulting movement of the object has a kind of continuity and fluidity that the original random walker lacked. It may seem subtle, but it fundamentally changes the way the object moves about the canvas.</p>
<div data-type="exercise">
<h3 id="exercise-16">Exercise 1.6</h3>
<p>Referring back to the <a href="/random#perlin-noise-a-smoother-approach">Chapter 0</a>, implement an acceleration calculated with Perlin noise.</p>
</div>
<h2 id="static-vs-non-static-methods">Static vs. Non-Static Methods</h2>
<p>You might have noticed something a bit odd and unfamiliar in the previous example. The <code>random2D()</code> method used to create a random unit vector was called on the class name itself, as in <code>p5.Vector.random2D()</code>, rather than on the current instance of the class, as in <code>this.random2D()</code>. This is because <code>random2D()</code> is a <strong>static method</strong>, meaning its associated with the class as a whole rather than the individual objects themselves (that is, the instances of that class).</p>
<p>Static methods are rarely needed when youre writing your own classes (like <code>Walker</code> or <code>Mover</code>), so you may not have encountered them before. They sometimes form an important part of prewritten classes like <code>p5.Vector</code>, however. In fact, Acceleration Algorithm #3 (accelerate toward the mouse), requires further use of this concept, so lets take a step back and consider the difference between static and non-static methods.</p>
<p>Setting aside vectors for a second, take a look at the following code:</p>
<pre class="codesplit" data-code-language="javascript">let x = 0;
let y = 5;
x = x + y;</pre>
<p>This is probably what youre used to, yes? <code>x</code> has a value of 0, add <code>y</code> to it, and now <code>x</code> is equal to 5. I could write similar code for adding two vectors:</p>
<pre class="codesplit" data-code-language="javascript">let v = createVector(0, 0);
let u = createVector(4, 5);
v.add(u);</pre>
<p>The vector <code>v</code> has the value of (0,0), I add the vector <code>u</code> to it, and now <code>v</code> is equal to (4,5). Makes sense, right?</p>
<p>Now consider this other example:</p>
<pre class="codesplit" data-code-language="javascript">let x = 0;
let y = 5;
let z = x + y;</pre>
<p><code>x</code> has a value of 0, I add <code>y</code> to it, and store the result in a new variable <code>z</code>. The value of <code>x</code> doesnt change here (neither does <code>y</code>)! This may seem like a trivial point, and one that is quite intuitive when it comes to mathematical operations with simple numbers. However, its not so obvious with mathematical operations using <code>p5.Vector</code> objects. Lets try to rewrite the example with vectors, based on what Ive covered of the <code>p5.Vector</code> class so far.</p>
<pre class="codesplit" data-code-language="javascript">let v = createVector(0, 0);
let u = createVector(4, 5);
// Dont be fooled; this is incorrect!!!
let w = v.add(u);</pre>
<p>This might seem like a good guess, but its just not the way the <code>p5.Vector</code> class works. If you look at the definition of <code>add()</code>, you can see why.</p>
<pre class="codesplit" data-code-language="javascript">add(v) {
this.x = this.x + v.x;
this.y = this.y + v.y;
}</pre>
<p>There are two problems here. First, the <code>add()</code> function doesnt return a new <code>p5.Vector</code> object, and second, it changes the value of the vector upon which its called. In order to add two vector objects together and return the result as a new vector, I must use the static version of the <code>add()</code> function by calling it on the class name itself, rather than calling the non-static version on a specific object instance.</p>
<p>Heres how I might write the static version of <code>add()</code> if I were declaring the class myself:</p>
<pre class="codesplit" data-code-language="javascript">//{!1} The static version adds two vectors together and assigns the result to a new vector while leaving the original vectors (v and u above) intact.
static add(v1, v2) {
let v3 = createVector(v1.x + v2.x, v1.y + v2.y);
return v3;
}</pre>
<p>The key difference here is that the function returns a new vector (<code>v3</code>) created using the sum of the components of <code>v1</code> and <code>v2</code>. As a result, the function doesnt make changes to either original vector.</p>
<p>When calling a static function, instead of referencing an object instance, you reference the name of the class itself. Heres the right way to implement the vector addition example:</p>
<pre class="codesplit" data-code-language="javascript">let v = createVector(0, 0);
let u = createVector(4, 5);
//{.line-through .no-comment}
let w = v.add(u);
//{.bold .no-comment}
let w = p5.Vector.add(v, u);</pre>
<p>The <code>p5.Vector</code> class has static versions of <code>add()</code>, <code>sub()</code>, <code>mult()</code>, and <code>div()</code>. These static functions allow you to perform generic mathematical operations on vectors without changing the value of one of the input vectors in the process.</p>
<div data-type="exercise">
<h3 id="exercise-17">Exercise 1.7</h3>
<p>Translate the following pseudocode to code using static or non-static functions where appropriate.</p>
<ul>
<li>The vector <code>v</code> equals (1,5).</li>
<li>The vector <code>u</code> equals <code>v</code> multiplied by 2.</li>
<li>The vector <code>w</code> equals <code>v</code> minus <code>u</code>.</li>
<li>Divide the vector w by 3.</li>
</ul>
<pre class="codesplit" data-code-language="javascript">let v = <span class="blank">createVector(1, 5)</span>;
let u = <span class="blank">p5.Vector.mult</span>(<span class="blank">v, 2</span>);
let w = <span class="blank">p5.Vector.sub</span>(<span class="blank">v, u</span>);
<span class="blank">w.div(3)</span>;</pre>
</div>
<h2 id="interactive-motion-acceleration-algorithm-3">Interactive Motion (Acceleration Algorithm #3)</h2>
<p>To finish out this chapter, lets try something a bit more complex and a great deal more useful. Ill dynamically calculate an objects acceleration according to the rule stated in Acceleration Algorithm #3: the object accelerates toward the mouse.</p>
<figure class="half-width-right">
<img src="images/01_vectors/01_vectors_15.png" alt="Figure 1.15 A vector from an object to the mouse position">
<figcaption>Figure 1.15 A vector from an object to the mouse position</figcaption>
</figure>
<p>Anytime you want to calculate a vector based on a rule or a formula, you need to compute two things: magnitude and direction. Ill start with direction. I know the acceleration vector should point from the objects position toward the mouse position (Figure 1.15). Lets say the object is located at the position vector <span data-type="equation">(x, y)</span> and the mouse at <span data-type="equation">(mouseX, mouseY)</span>.</p>
<figure class="half-width-right">
<img src="images/01_vectors/01_vectors_16.png" alt="Figure 1.16 Calculating an initial acceleration vector by taking the difference of. them ouse and position vectors">
<figcaption>Figure 1.16 Calculating an initial acceleration vector by taking the difference of. them ouse and position vectors</figcaption>
</figure>
<p>In Figure 1.16, you see that the acceleration vector <span data-type="equation">(dx,dy)</span> can be calculated by subtracting the objects position from the mouses position.</p>
<ul>
<li><span data-type="equation">dx = mouseX - x</span></li>
<li><span data-type="equation">dy = mouseY - y</span></li>
</ul>
<p>Lets implement that using <code>p5.Vector</code> syntax. Assuming the code will live inside the <code>Mover</code> class and thus have access to the objects <code>position</code>, I can write:</p>
<pre class="codesplit" data-code-language="javascript">let mouse = createVector(mouseX, mouseY);
// Look! Im using the static reference to sub() because I want a new p5.Vector!
let direction = p5.Vector.sub(mouse, this.position);</pre>
<p>Ive used the static version of <code>sub()</code> to createI a new vector <code>direction</code> that points from the movers position to the mouse. If the object were to actually accelerate using that vector, however, it would appear instantaneously at the mouse position, since the magnitude of <code>direction</code> is equal to the distance between the object and the mouse. This wouldnt make for a smooth animation, of course. The next step, therefore, is to decide how quickly the object should accelerate toward the mouse by changing the vectors magnitude.</p>
<p>In order to set the magnitude (whatever it may be) of the acceleration vector, I must first _____<em>_</em> the vector. Thats right, you said it: <em>normalize</em>! If I can shrink the vector down to its unit vector (of length 1), then I can easily scale it to any other value. One multiplied by anything equals anything.</p>
<pre class="codesplit" data-code-language="javascript">// Any number!
let anything = __________________;
direction.normalize();
direction.mult(anything);</pre>
<p>To summarize, follow these steps to make the object accelerate towards the mouse:</p>
<ol>
<li>Calculate a vector that points from the object to the target position (mouse).</li>
<li>Normalize that vector (reducing its length to 1).</li>
<li>Scale that vector to an appropriate value (by multiplying it by some value).</li>
<li>Assign that vector to acceleration.</li>
</ol>
<p>I have a confession to make. Normalization then scaling is such a common vector operation that <code>p5.Vector</code> includes a function that does both, setting the magnitude of a vector to a given value with a single function call. That function is <code>setMag()</code>.</p>
<pre class="codesplit" data-code-language="javascript">let anything = ?????
dir.setMag(anything);</pre>
<p>In this next example, to emphasize the math, Im going to write the code using <code>normalize()</code> and <code>mult()</code>, but this is likely the last time Ill do that. Youll find <code>setMag()</code> in examples going forward.</p>
<div data-type="example">
<h3 id="example-110-accelerating-toward-the-mouse">Example 1.10: Accelerating Toward the Mouse</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/gYJHm1EFL" data-example-path="examples/01_vectors/example_1_10_accelerating_towards_the_mouse"><img src="examples/01_vectors/example_1_10_accelerating_towards_the_mouse/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript"> update() {
let mouse = createVector(mouseX, mouseY);
// Step 1: Compute direction
let dir = p5.Vector.sub(mouse, this.position);
// Step 2: Normalize
dir.normalize();
// Step 3: Scale
dir.mult(0.2);
//{!1} Step 4: Accelerate
this.acceleration = dir;
this.velocity.add(this.acceleration);
this.velocity.limit(this.topspeed);
this.position.add(this.velocity);
}</pre>
<p>You may be wondering why the circle doesnt stop when it reaches the target. Its important to note that the object moving has no knowledge about trying to stop at a destination; it only knows where the destinations position is.The object tries to accelerate there at a fixed rate, regardless of how far away it is. This means it will inevitably overshoot the target and have to turn around, again accelerating toward the destination, overshooting it again, and so on and so forth. Stay tuned; in later chapters, Ill show you how to program an object to <strong>arrive</strong> at a target (slow down on approach).</p>
<div data-type="exercise">
<h3 id="exercise-18">Exercise 1.8</h3>
<p>Example 1.10 is remarkably close to the concept of gravitational attraction, with the object being attracted to the mouse position. In the example, however, the attraction magnitude is constant, whereas with a real-life gravitational force, the magnitude is inversely proportional to distance: the closer the object is to the attraction point, the faster it accelerates. Ill cover gravitational attraction in more detail in the next chapter, but for now, try implementing you own version of Example 1.10 with a variable magnitude of acceleration, stronger when its either closer or farther away.</p>
</div>
<div data-type="project">
<h3 id="the-ecosystem-project">The Ecosystem Project</h3>
<p><em>As mentioned in the preface, one way to use this book is to build a single project over the course of reading it, incorporating elements from each chapter as you go. One idea for this is a simulation of an ecosystem. Imagine a population of computational creatures swimming around a digital pond, interacting with each other according to various rules.</em></p>
<p>Step 1 Exercise:</p>
<p>Develop a set of rules for simulating the real-world behavior of a creature, such as a nervous fly, swimming fish, hopping bunny, slithering snake, and so on. Can you control the objects motion by only manipulating the acceleration vector? Try to give the creature a personality through its behavior (rather than through its visual design, although that is, of course, worth exploring as well).</p>
<p>Here's an illustration to help you generate ideas about how to build an ecosystem based on the topics covered in this book. Watch how the illustration evolves as new concepts and techniques are introduced with each subsequent chapter. The goal of this book is to demonstrate algorithms and behaviors, so my examples will almost always only include a single primitive shape, such as a circle. However, I fully expect that there are creative sparks within you, and encourage you to challenge yourself with the designs of the elements you draw on the canvas. If drawing with code is new to you, the book's illustrator, Zannah Marsh, has written a helpful guide that you can find in [TBD].</p>
<figure>
<img src="images/01_vectors/01_vectors_17.png" alt="">
<figcaption></figcaption>
</figure>
</div>
</section>