Notion - Update docs

This commit is contained in:
jasongao97 2023-02-06 20:54:30 +00:00 committed by GitHub
parent 984ac515f2
commit 13bafb353a
63 changed files with 896 additions and 140 deletions

View file

@ -165,8 +165,8 @@ 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>I'll note that in the above code the vector objects are not created, as you might expect, by invoking a constructor function. Instead of <code>new Vector(x, y)</code> (or more accurately in p5 <code>new p5.Vector(x, y)</code>), <code>createVector(x, y)</code> is called. The <code>createVector()</code> function is included in p5.js as a helper function to take care of details behind the scenes as well as simplify the code. Except in special circumstances, <code>p5.Vector</code> objects should always be created with <code>createVector()</code>.</p><a data-type="indexterm" data-primary="vectors" data-secondary="motion" data-tertiary="implementing with"></a>
<p>Now that I have two vector objects (position and velocity), Im ready to implement the algorithm for motion—<strong><em>position = position + velocity</em></strong>. In Example 1.1, without vectors, the code read:</p>
<p>I'll note that in the above code the vector objects are not created, as you might expect, by invoking a constructor function. Instead of <code>new Vector(x, y)</code> (or more accurately in p5 <code>new p5.Vector(x, y)</code>), <code>createVector(x, y)</code> is called. 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, <code>p5.Vector</code> objects should always be created with <code>createVector()</code>.</p><a data-type="indexterm" data-primary="vectors" data-secondary="motion" data-tertiary="implementing with"></a>
<p>Now that there are two vector objects (<code>position</code> and <code>velocity</code>), Im ready to implement the algorithm for motion—<strong><em>position = position + velocity</em></strong>. In Example 1.1, without vectors, the code read:</p>
<pre class="codesplit" data-code-language="javascript">// Add each speed to each position.
x = x + xspeed;
y = y + yspeed;</pre>
@ -183,13 +183,14 @@ position = position + velocity;</pre><a data-type="indexterm" data-primary="addi
</ul>
<p>Lets say I have the following two vectors:</p>
<figure>
<img src="images/01_vectors/01_vectors_5.png" alt="Figure 1.5: Two vectors ">
<figcaption>Figure 1.5: Two vectors</figcaption>
<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 <code>x</code> and a <code>y</code>. To add two vectors together, add both <code>x</code>s and both <code>y</code>s.</p>
<figure>
<img src="images/01_vectors/01_vectors_6.png" alt="Figure 1.6">
<figcaption>Figure 1.6</figcaption>
<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:</p>
<div data-type="equation">\vec{w} = \vec{u} + \vec{v}</div>
@ -204,7 +205,7 @@ position = position + velocity;</pre><a data-type="indexterm" data-primary="addi
<div data-type="equation">w_y = 6</div>
<p>Finally, writing that as a vector:</p>
<div data-type="equation">\vec{w} = (8,6)</div><a data-type="indexterm" data-primary="add() function (PVector class)" data-secondary="implementation of"></a>
<p>Now that I've covered how to add two vectors together, you can look at how addition is implemented in the <code>p5.Vector</code> class itself. Lets write a function called <code>add()</code> that takes another <code>Vector</code> object as its argument.</p>
<p>Now that I've covered how to add two vectors together, I can turn how addition is implemented in the <code>p5.Vector</code> class itself. Lets write 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) {
@ -212,7 +213,7 @@ position = position + velocity;</pre><a data-type="indexterm" data-primary="addi
this.y = y;
}
//{!4 .bold} New! A function to add another Vector to this Vector. Simply add the <em>x</em> components and the <em>y</em>; components together.
//{!4 .bold} New! A function to add another Vector to this Vector. Add the <em>x</em> components and the <em>y</em> components together.
add(v) {
this.y = this.y + v.y;
this.x = this.x + v.x;
@ -227,11 +228,12 @@ position = position + velocity;</pre><a data-type="indexterm" data-primary="addi
<div data-type="equation">3 + 2 = 2 + 3</div>
<div data-type="equation">(3 + 2) + 1 = 3 + (2 + 1)</div>
</div><a data-type="indexterm" data-primary="bouncing ball sketch" data-secondary="implementing with vectors"></a>
<p>Now that I've covered how <code>add()</code> is written inside of <code>p5.Vector</code>, I can return to the bouncing ball example with its <strong><em>position + velocity</em></strong> algorithm and implement vector addition:</p>
<pre class="codesplit" data-code-language="javascript">//{!1 .line-through} Add the current velocity to the position.
<p>Seeing how <code>add()</code> is written inside of <code>p5.Vector</code>, I can now return to the bouncing ball example with its <strong><em>position + velocity</em></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>And here I am, ready to rewrite the bouncing ball example using vectors.</p><a data-type="indexterm" data-primary="dot syntax"></a><a data-type="indexterm" data-primary="object-oriented programming" data-secondary="dot syntax"></a>
<p>And so it is time, time to rewrite the bouncing ball example with vectors.</p><a data-type="indexterm" data-primary="dot syntax"></a><a data-type="indexterm" data-primary="object-oriented programming" data-secondary="dot syntax"></a>
<div data-type="example">
<h3 id="example-12-bouncing-ball-with-vectors">Example 1.2: Bouncing ball with vectors!</h3>
<figure>
@ -265,14 +267,14 @@ function draw() {
stroke(0);
fill(175);
ellipse(position.x, position.y, 16, 16);
circle(position.x, position.y, 48);
}</pre>
<p>Now, you might feel somewhat disappointed. After all, this 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 I havent fully realized the power of programming with vectors just yet. Looking at a simple 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), the benefits of vectors will become more apparent.</p>
<p>Now, you might feel somewhat disappointed. After all, this 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), the benefits of vectors will become more apparent.</p>
<p>I should, however, note an important aspect of the above transition to programming with vectors. Even though I am using <code>p5.Vector</code> objects to describe two values—the <code>x</code> and <code>y</code> of position and the <code>x</code> and <code>y</code> of velocity—I will still often need to refer to the <em>x</em> and <em>y</em> components of each vector individually. When I go to draw an object in p5.js, theres no means to say:</p>
<pre class="codesplit" data-code-language="javascript">//{.line-through .no-comment}
ellipse(position, 16, 16);</pre>
<p>The <code>ellipse()</code> function does not allow for a <code>p5.Vector</code> as an argument. An ellipse can only be drawn with two scalar values, an <code>x</code>-coordinate and a <code>y</code>-coordinate. And so you must dig into the <code>p5.Vector</code> object and pull out the <em>x</em> and <em>y</em> components using object-oriented dot syntax.</p>
<pre class="codesplit" data-code-language="javascript">ellipse(position.x, position.y, 16, 16);</pre>
circle(position, 48);</pre>
<p>The <code>circle()</code> function does not allow for a <code>p5.Vector</code> as an argument. A circle can only be drawn with two scalar values, an <code>x</code>-coordinate and a <code>y</code>-coordinate. And so I must dig into the <code>p5.Vector</code> object and pull out the <em>x</em> and <em>y</em> components using object-oriented dot syntax.</p>
<pre class="codesplit" data-code-language="javascript">circle(position.x, position.y, 48);</pre>
<p>The same issue arises when testing if the circle has reached the edge of the window, and you 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;
@ -311,20 +313,23 @@ ellipse(position, 16, 16);</pre>
<li><code>random3D()</code> — make a random 3D vector</li>
</ul>
<p>Having already covered addition, lets start with subtraction. This ones not so bad; just take the plus sign and replace it with a minus!</p>
<h3 id="vector-subtraction">Vector subtraction</h3><a data-type="indexterm" data-primary="PVector class (Processing)" data-secondary="sub() function"></a><a data-type="indexterm" data-primary="sub() function (PVector class)"></a>
<figure class="half-width-right">
<img src="images/01_vectors/01_vectors_7.png" alt=" Figure 1.7a: the relationship between v and -v ">
<figcaption>Figure 1.7a: the relationship between v and -v </figcaption>
<h3 id="vector-subtraction">Vector subtraction</h3>
<p>Before tackling subtraction itself, lets consider what it means for <span data-type="equation">\vec{v}</span> to become <span data-type="equation">-\vec{v}</span>. The negative version of the scalar <code>3</code> is <code>-3</code>. A negative vector is the same, only each components polarity is inverted. So if <span data-type="equation">\vec{v}</span> has the components <code>(x, y)</code> then <span data-type="equation">-\vec{v}</span> is <code>(-x, -y)</code>. Visually, as depicted in Figure 1.7, this results in the arrow pointing in the opposite direction.</p><a data-type="indexterm" data-primary="PVector class (Processing)" data-secondary="sub() function"></a><a data-type="indexterm" data-primary="sub() function (PVector class)"></a>
<figure>
<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>Subtraction, then, is the same as addition but with a minus replacing a plus. The components themselves are subtracted.</p>
<div data-type="equation">\vec{w} = \vec{u} - \vec{v}</div>
<p>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>
<figure>
<img src="images/01_vectors/01_vectors_8.png" alt="Figure 1.7 Vector Subtraction">
<figcaption>Figure 1.7 Vector Subtraction</figcaption>
<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 direciton. ">
<figcaption>Figure 1.8 Showing Vector Subtraction as one vector placed at the end of another but pointing in the opposite direciton.</figcaption>
</figure>
<p>and so the function inside <code>p5.Vector</code> looks like:</p>
<p>And just as vectors are added by placing them end to end, a vector is subtracted by placing a vector pointed in the opposite direction at the end.</p>
<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;
@ -337,18 +342,15 @@ ellipse(position, 16, 16);</pre>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">function setup() {
createCanvas(640, 240);
}
function draw() {
<pre class="codesplit" data-code-language="javascript">function draw() {
background(255);
// Two p5.Vector, one for the mouse location and one for the center of the window
//{!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);
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);
@ -362,12 +364,8 @@ function draw() {
line(0, 0, mouse.x, mouse.y);
}</pre><a data-type="indexterm" data-primary="vectors" data-secondary="commutative" data-tertiary="associative rules of addition"></a>
<h3 id="vector-multiplication">Vector multiplication</h3><a data-type="indexterm" data-primary="mult() function (PVector class)"></a><a data-type="indexterm" data-primary="PVector class (Processing)" data-secondary="mult() function"></a><a data-type="indexterm" data-primary="vectors" data-secondary="multiplying"></a><a data-type="indexterm" data-primary="vectors" data-secondary="scaling"></a>
<p>Moving on to multiplication, you have to think a little bit differently. Multiplying a vector, typically refers to the process of <strong><em>scaling</em></strong> a vector. If I want to scale a vector to twice its size or one-third of its size (leaving its direction the same), I would say: “Multiply the vector by 2” or “Multiply the vector by 1/3.” Note that this is multiplying a vector by a scalar, a single number, not another vector.</p>
<p>Moving on to multiplication, you have to think a bit differently. Multiplying a vector typically refers to the process of <strong><em>scaling</em></strong> a vector. If I want to scale a vector to twice its size or one-third of its size (leaving its direction the same), I would say: “Multiply the vector by 2” or “Multiply the vector by 1/3.” Note that this is multiplying a vector by a <strong><em>scalar</em></strong>, a single number, not another vector.</p>
<p>To scale a vector, multiply each component (<code>x</code> and <code>y</code>) by a scalar.</p>
<figure class="half-width-right">
<img src="images/01_vectors/01_vectors_9.png" alt="Figure 1.8 Scaling a vector">
<figcaption>Figure 1.8 Scaling a vector</figcaption>
</figure>
<div data-type="equation">\vec{w} = \vec{u} * n</div>
<p>can be written as:</p>
<div data-type="equation">w_x = u_x * n</div>
@ -380,42 +378,50 @@ function draw() {
<div data-type="equation">w_y = 7 * 3</div>
<div data-type="equation">\vec{w} = (-9,21)</div>
<p>Therefore, the function inside the <code>p5.Vector</code> class is written as:</p>
<figure class="half-width-right">
<img src="images/01_vectors/01_vectors_9.png" alt="Figure 1.9 Scaling a vector">
<figcaption>Figure 1.9 Scaling a vector</figcaption>
</figure>
<pre class="codesplit" data-code-language="javascript">mult(n) {
//{!2} With multiplication, the components of the vector are multiplied by a number.
//{!2} The components of the vector are multiplied by a number.
this.x = this.x * n;
this.y = this.y * n;
}</pre>
<p>And implementing multiplication in code is as simple as:</p><a data-type="indexterm" data-primary="mult() function (PVector class)" data-secondary="implementation"></a>
<p>Implementing multiplication in code is as simple as:</p><a data-type="indexterm" data-primary="mult() function (PVector class)" data-secondary="implementation"></a>
<pre class="codesplit" data-code-language="javascript">let u = vector(-3, 7);
// This PVector is now three times the size and is equal to (-9, 21).
// This PVector is now three times the size and is equal to (-9, 21). (See Figure 1.9)
u.mult(3);</pre>
<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"></div>
<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 setup() {
createCanvas(640, 240);
}
function draw() {
<pre class="codesplit" data-code-language="javascript">function draw() {
background(255);
let mouse = createVector(mouseX, mouseY);
let center = createVector(width/2, height/2);
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);
translate(width/2, height/2);
stroke(0);
strokeWeight(4);
line(0, 0, mouse.x, mouse.y);
}</pre>
<figure class="half-width-right">
<img src="images/01_vectors/01_vectors_10.png" alt="Figure 1.9">
<figcaption>Figure 1.9</figcaption>
<figure>
<img src="images/01_vectors/01_vectors_10.png" alt="Figure 1.10">
<figcaption>Figure 1.10</figcaption>
</figure><a data-type="indexterm" data-primary="div() function (PVector class)"></a><a data-type="indexterm" data-primary="PVector class (Processing)" data-secondary="div() function"></a>
<p>Division works just like multiplication—simply replace the multiplication sign (asterisk) with the division sign (forward slash).</p>
<p>Division works just like multiplication—just replace the multiplication sign (asterisk, e.g. <code>*</code>) with the division sign (forward slash, e.g. <code>/</code>).</p>
<pre class="codesplit" data-code-language="javascript">div(n) {
this.x = this.x / n;
this.y = this.y / n;
@ -433,15 +439,15 @@ u.div(2);</pre><a data-type="indexterm" data-primary="vectors" data-secondary="a
</div>
<h2 id="15-vector-magnitude">1.5 Vector Magnitude</h2><a data-type="indexterm" data-primary="magnitude (of vectors)"></a><a data-type="indexterm" data-primary="vectors" data-secondary="magnitude"></a>
<figure class="half-width-right">
<img src="images/01_vectors/01_vectors_11.png" alt=" Figure 1.10: The length or “magnitude” of a vector \vec{v} is often written as: \lVert\vec{v}\rVert">
<figcaption>Figure 1.10: 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>
<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 I just described, change the length of a vector without affecting direction. Perhaps youre wondering: “OK, so how do I know what the length of a vector is? I know the components (<code>x</code> and <code>y</code>), but how long (in pixels) is the actual arrow?” Understanding how to calculate the length (also known as <strong><em>magnitude</em></strong>) of a vector is incredibly useful and important.</p><a data-type="indexterm" data-primary="Pythagoras"></a><a data-type="indexterm" data-primary="Pythagorean theorem"></a>
<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 components (<code>x</code> and <code>y</code>), but how long (in pixels) is the actual arrow?” Understanding how to calculate the length (also known as <strong><em>magnitude</em></strong>) of a vector is incredibly useful and important.</p><a data-type="indexterm" data-primary="Pythagoras"></a><a data-type="indexterm" data-primary="Pythagorean theorem"></a>
<figure class="half-width-right">
<img src="images/01_vectors/01_vectors_12.png" alt="Figure 1.11: The Pythagorean Theorem">
<figcaption>Figure 1.11: The Pythagorean Theorem</figcaption>
<img src="images/01_vectors/01_vectors_12.png" alt="Figure 1.12: The Pythagorean Theorem is used to calculate the length of a vector from its components.">
<figcaption>Figure 1.12: The Pythagorean Theorem is used to calculate the length of a vector from its components.</figcaption>
</figure>
<p>Notice in Figure 1.10 how the vector, drawn as an arrow and two components (<code>x</code> and <code>y</code>), 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 to describe the relationship between the sides and hypotenuse of a right triangle.</p>
<p>Notice in Figure 1.11 how the vector, drawn as an arrow and two components (<code>x</code> and <code>y</code>), 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.</p>
<p>The Pythagorean theorem is <em>a</em> squared plus <em>b</em> squared equals <em>c</em> squared, for right triangles.</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>
@ -452,7 +458,7 @@ u.div(2);</pre><a data-type="indexterm" data-primary="vectors" data-secondary="a
<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"></div>
<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><a data-type="indexterm" data-primary="mag() function (PVector class)"></a><a data-type="indexterm" data-primary="PVector class (Processing)" data-secondary="mag() function"></a>
@ -477,16 +483,16 @@ function draw() {
}</pre>
<h2 id="16-normalizing-vectors">1.6 Normalizing Vectors</h2><a data-type="indexterm" data-primary="normalization"></a><a data-type="indexterm" data-primary="unit vectors"></a><a data-type="indexterm" data-primary="vectors" data-secondary="normalization"></a><a data-type="indexterm" data-primary="vectors" data-secondary="unit vectors"></a>
<figure class="half-width-right">
<img src="images/01_vectors/01_vectors_13.png" alt="Figure 1.12">
<figcaption>Figure 1.12</figcaption>
<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 it is resized to a “unit” length of 1.">
<figcaption>Figure 1.13 When a vector is normalized it points in the same direction but it is resized to a “unit” length of 1.</figcaption>
</figure>
<p>Calculating the magnitude of a vector is only the beginning. The magnitude function opens the door to many possibilities, the first of which is <strong><em>normalization</em></strong>. Normalizing refers to the process of making something “standard” or, well, “normal.” In the case of vectors, lets assume for the moment that a standard vector has a length of 1. To normalize a vector, therefore, is to take a vector of any length and, keeping it pointing in the same direction, change its length to 1, turning it into what is called a <strong><em>unit vector</em></strong>.</p>
<p>Calculating the magnitude of a vector is only the beginning. The <code>mag()</code> opens the door to many possibilities, the first of which is <strong><em>normalization</em></strong>. Normalizing refers to 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, keeping it pointing in the same direction, change its length to 1. That vector is then called a <strong><em>unit vector</em></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.13">
<figcaption>Figure 1.13</figcaption>
<img src="images/01_vectors/01_vectors_14.png" alt="Figure 1.14">
<figcaption>Figure 1.14</figcaption>
</figure>
<p>In other words, to normalize a vector, divide each component by its magnitude. This is pretty intuitive. Say a vector is of length 5. Well, 5 divided by 5 is 1. So, looking at a right triangle, you then need to scale the hypotenuse down by dividing by 5. In that process the sides shrink, divided by 5 as well.</p><a data-type="indexterm" data-primary="normalize() function (PVector class)"></a><a data-type="indexterm" data-primary="PVector class (Processing)" data-secondary="normalize() function"></a>
<p>In the <code>p5.Vector</code> class, the normalization function is written as follows:</p>

View file

@ -191,7 +191,7 @@ mover.applyForce(wind);</pre>
<div data-type="example">
<h3 id="example-21-forces">Example 2.1: Forces</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/4IRI8BEVE" data-example-path="examples/02_forces/example_2_1_forces"></div>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/4IRI8BEVE" data-example-path="examples/02_forces/example_2_1_forces"><img src="examples/02_forces/example_2_1_forces/screenshot.png"></div>
<figcaption>Click mouse to apply wind force.</figcaption>
</figure>
</div>
@ -284,12 +284,8 @@ let moverB = new Mover(400, 30, 2);</pre>
<div data-type="example">
<h3 id="example-22-forces-acting-on-two-objects">Example 2.2: Forces acting on two objects</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/SJC2hk-dl"></div>
<figcaption></figcaption>
</figure>
<figure>
<img src="images/02_forces/02_forces_3.png" alt="">
<figcaption></figcaption>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/ePLfo-OGu" data-example-path="examples/02_forces/example_2_2_forces_acting_on_two_objects"><img src="examples/02_forces/example_2_2_forces_acting_on_two_objects/screenshot.png"></div>
<figcaption>Click mouse to apply wind force.</figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">function draw() {
@ -332,12 +328,8 @@ let moverB = new Mover(400, 30, 2);</pre>
<div data-type="example">
<h3 id="example-23-gravity-scaled-by-mass">Example 2.3: Gravity scaled by mass</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/HyQea1W_l"></div>
<figcaption></figcaption>
</figure>
<figure>
<img src="images/02_forces/02_forces_4.png" alt="">
<figcaption></figcaption>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/0RiwMFOQ7" data-example-path="examples/02_forces/example_2_3_gravity_scaled_by_mass"><img src="examples/02_forces/example_2_3_gravity_scaled_by_mass/screenshot.png"></div>
<figcaption>Click mouse to apply wind force.</figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">// Made-up gravity force
@ -382,7 +374,7 @@ moverB.applyForce(gravityB);</pre>
<p>Friction is a <strong><em>dissipative force</em></strong>. A dissipative force is one in which the total energy of a system decreases when an object is in motion. Lets say you are driving a car. When you press your foot down on the brake pedal, the cars brakes use friction to slow down the motion of the tires. Kinetic energy (motion) is converted into thermal energy (heat). Whenever two surfaces come into contact, they experience friction. A complete model of friction would include separate cases for static friction (a body at rest against a surface) and kinetic friction (a body in motion against a surface), but for simplification here, I am only going to look at the kinetic case.</p>
<p>Figure 2.3 shows the formula for friction.</p>
<figure>
<img src="images/02_forces/02_forces_5.png" alt="Figure 2.3">
<img src="images/02_forces/02_forces_3.png" alt="Figure 2.3">
<figcaption>Figure 2.3</figcaption>
</figure><a data-type="indexterm" data-primary="friction" data-secondary="determining direction" data-tertiary="magnitude of"></a>
<p>Its now time to separate this formula into two components that determine the direction of friction as well as the magnitude. Figure 2.3 indicates that <em>friction points in the opposite direction of velocity.</em> In fact, thats the part of the formula that says -1 * <span data-type="equation">\hat{v}</span>, or -1 times the velocity unit vector. In p5.js, this would mean taking the velocity vector and multiplying by -1.</p>
@ -430,12 +422,8 @@ friction.mult(frictionMag);
<div data-type="example">
<h3 id="example-24-including-friction">Example 2.4: Including friction</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/B1isyebug"></div>
<figcaption></figcaption>
</figure>
<figure>
<img src="images/02_forces/02_forces_6.png" alt="The circle eventually rolls to a stop with friction.">
<figcaption>The circle eventually rolls to a stop with friction.</figcaption>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/I4wC4aXd-E" data-example-path="examples/02_forces/example_2_4_including_friction"><img src="examples/02_forces/example_2_4_including_friction/screenshot.png"></div>
<figcaption>Click mouse to apply wind force.</figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">function draw() {
@ -476,7 +464,7 @@ friction.mult(frictionMag);
</div>
<h2 id="28-air-and-fluid-resistance">2.8 Air and Fluid Resistance</h2>
<figure>
<img src="images/02_forces/02_forces_7.png" alt="Figure 2.4">
<img src="images/02_forces/02_forces_4.png" alt="Figure 2.4">
<figcaption>Figure 2.4</figcaption>
</figure><a data-type="indexterm" data-primary="drag force"></a><a data-type="indexterm" data-primary="fluid resistance" data-secondary="modeling"></a><a data-type="indexterm" data-primary="forces" data-secondary="fluid resistance"></a><a data-type="indexterm" data-primary="natural phenomena" data-secondary="fluid resistance" data-tertiary="modeling"></a><a data-type="indexterm" data-primary="viscous force"></a>
<p>Friction also occurs when a body passes through a liquid or gas. This force has many different names, all really meaning the same thing: <em>viscous force</em>, <em>drag force</em>, <em>fluid resistance</em>. While the result is ultimately the same as our previous friction examples (the object slows down), the calculation of a drag force is slightly different. Lets look at the formula:</p>
@ -495,7 +483,7 @@ friction.mult(frictionMag);
</ul>
<p>Now that Ive analyzed each of these components and determined what is needed for a simple simulation, I can reduce the formula to:</p>
<figure>
<img src="images/02_forces/02_forces_8.png" alt="Figure 2.5: My simplified drag force formula ">
<img src="images/02_forces/02_forces_5.png" alt="Figure 2.5: My simplified drag force formula ">
<figcaption>Figure 2.5: My simplified drag force formula </figcaption>
</figure>
<p>or:</p>
@ -564,14 +552,10 @@ if (liquid.contains(mover) {
}</pre>
<p>And with these two functions added to the <code>Liquid</code> class, Im ready to put it all together! In the following example, Ill expand the code to use an array (with mover objects spaced out evenly) to demonstrate how the drag force behaves with objects of variable mass.</p>
<div data-type="example">
<h3 id="example-25-fluid-resistance">Example 2.5: Fluid Resistance </h3>
<h3 id="example-25-fluid-resistance">Example 2.5: Fluid Resistance</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/H1DmxeW_g"></div>
<figcaption></figcaption>
</figure>
<figure>
<img src="images/02_forces/02_forces_9.png" alt="">
<figcaption></figcaption>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/FknzcAaVh" data-example-path="examples/02_forces/example_2_5_fluid_resistance"><img src="examples/02_forces/example_2_5_fluid_resistance/screenshot.png"></div>
<figcaption>Click mouse to reset.</figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">let movers = [];
@ -625,7 +609,7 @@ function draw() {
</div>
<h2 id="29-gravitational-attraction">2.9 Gravitational Attraction</h2><a data-type="indexterm" data-primary="gravity" data-secondary="modeling"></a><a data-type="indexterm" data-primary="natural phenomena" data-secondary="gravity"></a>
<figure class="half-width-right">
<img src="images/02_forces/02_forces_10.png" alt=" Figure 2.6">
<img src="images/02_forces/02_forces_6.png" alt=" Figure 2.6">
<figcaption>Figure 2.6</figcaption>
</figure>
<p>Probably the most famous force of all is gravity. We humans on earth think of gravity as an apple hitting Isaac Newton on the head. Gravity means that stuff falls down. But this is only <em>our</em> experience of gravity. In truth, just as the earth pulls the apple towards it due to a gravitational force, the apple pulls the earth as well. The thing is, the earth is just so freaking big that it overwhelms all the other gravity interactions. Every object with mass exerts a gravitational force on every other object (this is Newtons third law). And there is a formula for calculating the strengths of these forces, as depicted in Figure 2.6.</p>
@ -646,7 +630,7 @@ function draw() {
</ol>
<p>Given these assumptions, I want to compute a vector, the force of gravity. Ill do it in two parts. First, Ill compute the direction of the force <span data-type="equation">\hat{r}</span> in the formula above. Second, Ill calculate the strength of the force according to the masses and distance.</p>
<figure class="half-width-right">
<img src="images/02_forces/02_forces_11.png" alt="Figure 2.7">
<img src="images/02_forces/02_forces_7.png" alt="Figure 2.7">
<figcaption>Figure 2.7</figcaption>
</figure>
<p>Remember in <a href="/vectors#110-interactivity-with-acceleration">Chapter 1</a>, when I created an example of an object accelerating towards the mouse? (See Figure 2.7.)</p>
@ -660,15 +644,10 @@ dir.normalize();</pre>
<pre class="codesplit" data-code-language="javascript">let magnitude = (G * mass1 * mass2) / (distance * distance);
dir.mult(magnitude);</pre>
<figure class="half-width-right">
<img src="images/02_forces/02_forces_12.png" alt="Figure 2.8">
<img src="images/02_forces/02_forces_8.png" alt="Figure 2.8">
<figcaption>Figure 2.8</figcaption>
</figure>
<div class="col-list">
<div>
<p></p>
</div>
<div>
<pre class="codesplit" data-code-language="javascript">//{!1} The vector that points from one object to another
<pre class="codesplit" data-code-language="javascript">//{!1} The vector that points from one object to another
let force = p5.Vector.sub(position1, position2);
//{!1} The length (magnitude) of that vector is the distance between the two objects.
@ -679,14 +658,12 @@ let magnitude = (G * mass1 * mass2) / (distance * distance);
//{!1} Normalize and scale the force vector to the appropriate magnitude.
force.setMag(magnitude);</pre>
</div>
</div>
<p>The only problem is that I dont know the distance. <code>G</code>, <code>mass1</code>, and <code>mass2</code> are all givens, but I need to calculate <code>distance</code> before the above code will work. Didnt I just make a vector that points all the way from one position to another? Wouldnt the length of that vector be the distance between the two objects?</p>
<p>Indeed, if I add one more line of code and grab the magnitude of that vector before normalizing it, then Ill have the distance. And this time, Ill skip the <code>normalize()</code> step and use <code>setMag()</code>.</p>
<p>Note that I also renamed the vector <code>dir</code> to <code>force</code>. After all, when the calculations are finished, the vector I started with ends up being the actual force vector I wanted all along.</p>
<p>Now that Ive worked out the math and code for calculating an attractive force (emulating gravity), lets turn our attention to applying this technique in the context of an actual p5.js sketch. In Example 2.1, I set up the foundation for all of these examples, a <code>Mover</code> class—a template for making objects with <code>p5.Vector</code> objects for position, velocity, and acceleration as well as an <code>applyForce()</code> method. Lets take this exact class and put it in a sketch with:</p>
<figure class="half-width-right">
<img src="images/02_forces/02_forces_13.png" alt="Figure 2.9">
<img src="images/02_forces/02_forces_9.png" alt="Figure 2.9">
<figcaption>Figure 2.9</figcaption>
</figure>
<ul>
@ -805,9 +782,9 @@ mover.applyForce(force);</pre>
<p>Now, its really up to you to decide what behaviors you want. But in the case of, “I want reasonable-looking attraction that is never absurdly weak or strong,” then constraining the distance is a good technique.</p>
<p>The <code>Mover</code> class hasnt changed at all, so lets just look at the main sketch and the <code>Attractor</code> class as a whole, adding a variable <code>G</code> for the universal gravitational constant. (On the website, youll find that this example also has code that allows you to move the <code>Attractor</code> object with the mouse.)</p>
<div data-type="example">
<h3 id="example-26-attraction">Example 2.6: Attraction </h3>
<h3 id="example-26-attraction">Example 2.6: Attraction</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/16sblEvax" data-example-path="examples/02_forces/noc_2_06_attraction"></div>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/16sblEvax" data-example-path="examples/02_forces/example_2_6_attraction"><img src="examples/02_forces/example_2_6_attraction/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
@ -863,11 +840,7 @@ class Attractor {
<div data-type="example">
<h3 id="example-27-attraction-with-many-movers">Example 2.7: Attraction with many Movers</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/rJ9l-x-Ox"></div>
<figcaption></figcaption>
</figure>
<figure>
<img src="images/02_forces/02_forces_14.png" alt="">
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/LSXJ6-VziJ" data-example-path="examples/02_forces/example_2_7_attraction_with_many_movers"><img src="examples/02_forces/example_2_7_attraction_with_many_movers/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
@ -961,11 +934,7 @@ function draw() {
<div data-type="example">
<h3 id="example-28-mutual-attraction">Example 2.8: Mutual attraction</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/SkYSWlb_x"></div>
<figcaption></figcaption>
</figure>
<figure>
<img src="images/02_forces/02_forces_15.png" alt="">
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/uT9VpVvCO" data-example-path="examples/02_forces/example_2_8_mutual_attraction"><img src="examples/02_forces/example_2_8_mutual_attraction/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
@ -1002,7 +971,7 @@ function draw() {
<p>Step 2 Exercise:</p>
<p>Incorporate the concept of forces into your ecosystem. Try introducing other elements into the environment (food, a predator) for the creature to interact with. Does the creature experience attraction or repulsion to things in its world? Can you think more abstractly and design forces based on the creatures desires or goals?</p>
<figure>
<img src="images/02_forces/02_forces_16.png" alt="">
<img src="images/02_forces/02_forces_10.png" alt="">
<figcaption></figcaption>
</figure>
<p></p>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View file

@ -10,13 +10,23 @@ function setup() {
function draw() {
background(255);
// Two vectors, one for the mouse position and one for the center of the window
let mouse = createVector(mouseX, mouseY);
let center = createVector(width / 2, height / 2);
// Draw the original two vectors
strokeWeight(4);
stroke(200);
line(0, 0, mouse.x, mouse.y);
line(0, 0, center.x, center.y);
// Vector subtraction!
mouse.sub(center);
translate(width / 2, height / 2);
strokeWeight(2);
// 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);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View file

@ -5,21 +5,29 @@
// Example 1-4: Vector multiplication
function setup() {
createCanvas(640,240);
createCanvas(640, 240);
}
function setup() {
createCanvas(640, 240);
}
function draw() {
background(255);
let mouse = createVector(mouseX,mouseY);
let center = createVector(width/2,height/2);
let mouse = createVector(mouseX, mouseY);
let center = createVector(width / 2, height / 2);
mouse.sub(center);
// Multiplying a vector! The vector is now half its original size (multiplied by 0.5).
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);
translate(width/2,height/2);
strokeWeight(2);
stroke(0);
line(0,0,mouse.x,mouse.y);
strokeWeight(4);
line(0, 0, mouse.x, mouse.y);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View file

@ -5,22 +5,25 @@
// Example 1-5: Vector magnitude
function setup() {
createCanvas(640,240);
createCanvas(640, 240);
}
function setup() {
createCanvas(640, 240);
}
function draw() {
background(255);
let mouse = createVector(mouseX,mouseY);
let center = createVector(width/2,height/2);
let mouse = createVector(mouseX, mouseY);
let center = createVector(width / 2, height / 2);
mouse.sub(center);
let m = mouse.mag();
fill(127);
stroke(0);
strokeWeight(2);
rect(0,0,m,10);
//{!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.
const m = mouse.mag();
fill(0);
rect(10, 10, m, 10);
translate(width/2,height/2);
line(0,0,mouse.x,mouse.y);
translate(width / 2, height / 2);
line(0, 0, mouse.x, mouse.y);
}

View file

@ -24,7 +24,7 @@ class Mover {
display() {
stroke(0);
strokeWeight(2);
fill(127);
fill(127, 127);
ellipse(this.position.x, this.position.y, 48, 48);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

View file

@ -0,0 +1,12 @@
<!doctype html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<script src="mover.js"></script>
<script src="sketch.js"></script>
</body>
</html>

View file

@ -0,0 +1,45 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
class Mover {
constructor(x, y, m) {
this.mass = m;
this.position = createVector(x, y);
this.velocity = createVector(0, 0);
this.acceleration = createVector(0, 0);
}
applyForce(force) {
let f = p5.Vector.div(force, this.mass);
this.acceleration.add(f);
}
update() {
this.velocity.add(this.acceleration);
this.position.add(this.velocity);
this.acceleration.mult(0);
}
display() {
stroke(0);
strokeWeight(2);
fill(127, 127);
ellipse(this.position.x, this.position.y, this.mass * 16, this.mass * 16);
}
checkEdges() {
if (this.position.x > width) {
this.position.x = width;
this.velocity.x *= -1;
} else if (this.position.x < 0) {
this.velocity.x *= -1;
this.position.x = 0;
}
if (this.position.y > height) {
this.velocity.y *= -1;
this.position.y = height;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View file

@ -0,0 +1,37 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
let moverA;
let moverB;
function setup() {
createCanvas(640, 240);
// A large Mover on the left side of the window
moverA = new Mover(200, 30, 10);
// A smaller Mover on the right side of the window
moverB = new Mover(440, 30, 2);
createP('Click mouse to apply wind force.');
}
function draw() {
background(255);
let gravity = createVector(0, 0.1);
moverA.applyForce(gravity);
moverB.applyForce(gravity);
if (mouseIsPressed) {
let wind = createVector(0.1, 0);
moverA.applyForce(wind);
moverB.applyForce(wind);
}
moverA.update();
moverA.display();
moverA.checkEdges();
moverB.update();
moverB.display();
moverB.checkEdges();
}

View file

@ -0,0 +1,12 @@
<!doctype html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<script src="mover.js"></script>
<script src="sketch.js"></script>
</body>
</html>

View file

@ -0,0 +1,46 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
class Mover {
constructor(x, y, m) {
this.mass = m;
this.radius = m * 8;
this.position = createVector(x, y);
this.velocity = createVector(0, 0);
this.acceleration = createVector(0, 0);
}
applyForce(force) {
let f = p5.Vector.div(force, this.mass);
this.acceleration.add(f);
}
update() {
this.velocity.add(this.acceleration);
this.position.add(this.velocity);
this.acceleration.mult(0);
}
display() {
stroke(0);
strokeWeight(2);
fill(127, 127);
ellipse(this.position.x, this.position.y, this.radius * 2);
}
checkEdges() {
if (this.position.x > width - this.radius) {
this.position.x = width - this.radius;
this.velocity.x *= -1;
} else if (this.position.x < this.radius) {
this.position.x = this.radius;
this.velocity.x *= -1;
}
if (this.position.y > height - this.radius) {
this.position.y = height - this.radius;
this.velocity.y *= -1;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

View file

@ -0,0 +1,41 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
let moverA;
let moverB;
function setup() {
createCanvas(640, 240);
// A large Mover on the left side of the window
moverA = new Mover(200, 30, 10);
// A smaller Mover on the right side of the window
moverB = new Mover(440, 30, 2);
createP('Click mouse to apply wind force.');
}
function draw() {
background(255);
let gravity = createVector(0, 0.1);
let gravityA = p5.Vector.mult(gravity, moverA.mass);
moverA.applyForce(gravityA);
let gravityB = p5.Vector.mult(gravity, moverB.mass);
moverB.applyForce(gravityB);
if (mouseIsPressed) {
let wind = createVector(0.1, 0);
moverA.applyForce(wind);
moverB.applyForce(wind);
}
moverA.update();
moverA.display();
moverA.checkEdges();
moverB.update();
moverB.display();
moverB.checkEdges();
}

View file

@ -0,0 +1,7 @@
html, body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}

View file

@ -0,0 +1,12 @@
<!doctype html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<script src="mover.js"></script>
<script src="sketch.js"></script>
</body>
</html>

View file

@ -0,0 +1,54 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
class Mover {
constructor(x, y, m) {
this.mass = m;
this.radius = m * 8;
this.position = createVector(x, y);
this.velocity = createVector(0, 0);
this.acceleration = createVector(0, 0);
}
applyForce(force) {
let f = p5.Vector.div(force, this.mass);
this.acceleration.add(f);
}
update() {
this.velocity.add(this.acceleration);
this.position.add(this.velocity);
this.acceleration.mult(0);
}
display() {
stroke(0);
strokeWeight(2);
fill(127, 127);
ellipse(this.position.x, this.position.y, this.radius * 2);
}
contactEdge() {
// The mover is touching the edge when it's within one pixel
return (this.position.y > height - this.radius - 1);
}
bounceEdges() {
// A new variable to simulate an inelastic collision
// 10% of the velocity's x or y component is lost
let bounce = -0.9;
if (this.position.x > width - this.radius) {
this.position.x = width - this.radius;
this.velocity.x *= bounce;
} else if (this.position.x < this.radius) {
this.position.x = this.radius;
this.velocity.x *= bounce;
}
if (this.position.y > height - this.radius) {
this.position.y = height - this.radius;
this.velocity.y *= bounce;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

View file

@ -0,0 +1,39 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
let mover;
function setup() {
createCanvas(640, 240);
mover = new Mover(width / 2, 30, 5);
createP('Click mouse to apply wind force.');
}
function draw() {
background(255);
let gravity = createVector(0, 1);
//{!1} I should scale by mass to be more accurate, but this example only has one circle
mover.applyForce(gravity);
if (mouseIsPressed) {
let wind = createVector(0.5, 0);
mover.applyForce(wind);
}
if (mover.contactEdge()) {
//{!5 .bold}
let c = 0.1;
let friction = mover.velocity.copy();
friction.mult(-1);
friction.setMag(c);
//{!1 .bold} Apply the friction force vector to the object.
mover.applyForce(friction);
}
mover.bounceEdges();
mover.update();
mover.display();
}

View file

@ -0,0 +1,7 @@
html, body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}

View file

@ -0,0 +1,13 @@
<!doctype html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<script src="mover.js"></script>
<script src="liquid.js"></script>
<script src="sketch.js"></script>
</body>
</html>

View file

@ -0,0 +1,43 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
class Liquid {
constructor(x, y, w, h, c) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.c = c;
}
// Is the Mover in the Liquid?
contains(mover) {
let l = mover.position;
return l.x > this.x && l.x < this.x + this.w &&
l.y > this.y && l.y < this.y + this.h;
}
// Calculate drag force
calculateDrag(mover) {
// Magnitude is coefficient * speed squared
let speed = mover.velocity.mag();
let dragMagnitude = this.c * speed * speed;
// Direction is inverse of velocity
let dragForce = mover.velocity.copy();
dragForce.mult(-1);
// Scale according to magnitude
// dragForce.setMag(dragMagnitude);
dragForce.normalize();
dragForce.mult(dragMagnitude);
return dragForce;
}
display() {
noStroke();
fill(200);
rect(this.x, this.y, this.w, this.h);
}
}

View file

@ -0,0 +1,43 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
class Mover {
constructor(x, y, mass) {
this.mass = mass;
this.radius = mass * 8;
this.position = createVector(x, y);
this.velocity = createVector(0, 0);
this.acceleration = createVector(0, 0);
}
// Newton's 2nd law: F = M * A
// or A = F / M
applyForce(force) {
let f = p5.Vector.div(force, this.mass);
this.acceleration.add(f);
}
update() {
// Velocity changes according to acceleration
this.velocity.add(this.acceleration);
// position changes by velocity
this.position.add(this.velocity);
// We must clear acceleration each frame
this.acceleration.mult(0);
}
display() {
stroke(0);
strokeWeight(2);
fill(127, 127);
ellipse(this.position.x, this.position.y, this.radius * 2);
}
// Bounce off bottom of window
checkEdges() {
if (this.position.y > height - this.radius) {
this.velocity.y *= -0.9; // A little dampening when hitting the bottom
this.position.y = height - this.radius;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View file

@ -0,0 +1,66 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// Forces (Gravity and Fluid Resistence) with Vectors
// Demonstration of multiple force acting on bodies (Mover class)
// Bodies experience gravity continuously
// Bodies experience fluid resistance when in "water"
// Five moving bodies
let movers = [];
// Liquid
let liquid;
function setup() {
createCanvas(640, 240);
reset();
// Create liquid object
liquid = new Liquid(0, height / 2, width, height / 2, 0.1);
createP("Click mouse to reset.");
}
function draw() {
background(255);
// Draw water
liquid.display();
for (let i = 0; i < movers.length; i++) {
// Is the Mover in the liquid?
if (liquid.contains(movers[i])) {
// Calculate drag force
let dragForce = liquid.calculateDrag(movers[i]);
// Apply drag force to Mover
movers[i].applyForce(dragForce);
}
// Gravity is scaled by mass here!
let gravity = createVector(0, 0.1 * movers[i].mass);
// Apply gravity
movers[i].applyForce(gravity);
// Update and display
movers[i].update();
movers[i].display();
movers[i].checkEdges();
}
}
// Not working???
function mousePressed() {
reset();
}
// Restart all the Mover objects randomly
function reset() {
for (let i = 0; i < 9; i++) {
movers[i] = new Mover(40 + i * 70, 0, random(0.5, 3));
}
}

View file

@ -0,0 +1,7 @@
html, body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}

View file

@ -29,7 +29,7 @@ class Mover {
display() {
stroke(0);
strokeWeight(2);
fill(0, 127);
fill(127, 127);
ellipse(this.position.x, this.position.y, this.radius * 2);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View file

@ -10,9 +10,8 @@ let attractor;
// Gravitational constant (for global scaling)
let G = 1;
function setup() {
createCanvas(640, 360);
createCanvas(640, 240);
mover = new Mover(300, 50, 2);
attractor = new Attractor();
}

View file

@ -0,0 +1,7 @@
html, body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}

View file

@ -0,0 +1,76 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// An object for a draggable attractive body in our world
class Attractor {
constructor() {
this.position = createVector(width / 2, height / 2);
this.mass = 20;
this.G = 1;
this.dragOffset = createVector(0, 0);
this.dragging = false;
this.rollover = false;
}
attract(mover) {
// Calculate direction of force
let force = p5.Vector.sub(this.position, mover.position);
// Distance between objects
let distance = force.mag();
// Limiting the distance to eliminate "extreme" results for very close or very far objects
distance = constrain(distance, 5, 25);
// Calculate gravitional force magnitude
let strength = (this.G * this.mass * mover.mass) / (distance * distance);
// Get force vector --> magnitude * direction
force.setMag(strength);
return force;
}
// Method to display
display() {
ellipseMode(CENTER);
strokeWeight(4);
stroke(0);
if (this.dragging) {
fill(50);
} else if (this.rollover) {
fill(100);
} else {
fill(175, 200);
}
ellipse(this.position.x, this.position.y, this.mass * 2, this.mass * 2);
}
// The methods below are for mouse interaction
handlePress(mx, my) {
let d = dist(mx, my, this.position.x, this.position.y);
if (d < this.mass) {
this.dragging = true;
this.dragOffset.x = this.position.x - mx;
this.dragOffset.y = this.position.y - my;
}
}
handleHover(mx, my) {
let d = dist(mx, my, this.position.x, this.position.y);
if (d < this.mass) {
this.rollover = true;
} else {
this.rollover = false;
}
}
stopDragging() {
this.dragging = false;
}
handleDrag(mx, my) {
if (this.dragging) {
this.position.x = mx + this.dragOffset.x;
this.position.y = my + this.dragOffset.y;
}
}
}

View file

@ -0,0 +1,13 @@
<!doctype html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<script src="mover.js"></script>
<script src="attractor.js"></script>
<script src="sketch.js"></script>
</body>
</html>

View file

@ -0,0 +1,35 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
class Mover {
constructor(x, y, mass) {
this.mass = mass;
this.radius = mass * 8;
this.position = createVector(x, y);
this.velocity = createVector(1, 0);
this.acceleration = createVector(0, 0);
}
// Newton's 2nd law: F = M * A
// or A = F / M
applyForce(force) {
let f = p5.Vector.div(force, this.mass);
this.acceleration.add(f);
}
update() {
// Velocity changes according to acceleration
this.velocity.add(this.acceleration);
// position changes by velocity
this.position.add(this.velocity);
// We must clear acceleration each frame
this.acceleration.mult(0);
}
display() {
stroke(0);
strokeWeight(2);
fill(127, 127);
ellipse(this.position.x, this.position.y, this.radius * 2);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

View file

@ -0,0 +1,45 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
let movers = [];
let attractor;
function setup() {
createCanvas(640, 240);
for (let i = 0; i < 10; i++) {
movers[i] = new Mover(random(width), random(height), random(0.5, 3));
}
attractor = new Attractor();
}
function draw() {
background(255);
attractor.display();
for (let i = 0; i < movers.length; i++) {
let force = attractor.attract(movers[i]);
movers[i].applyForce(force);
movers[i].update();
movers[i].display();
}
}
function mouseMoved() {
attractor.handleHover(mouseX, mouseY);
}
function mousePressed() {
attractor.handlePress(mouseX, mouseY);
}
function mouseDragged() {
attractor.handleHover(mouseX, mouseY);
attractor.handleDrag(mouseX, mouseY);
}
function mouseReleased() {
attractor.stopDragging();
}

View file

@ -0,0 +1,7 @@
html, body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}

View file

@ -0,0 +1,12 @@
<!doctype html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<script src="mover.js"></script>
<script src="sketch.js"></script>
</body>
</html>

View file

@ -0,0 +1,45 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
class Mover {
constructor(x, y, m) {
this.mass = m;
this.position = createVector(x, y);
this.velocity = createVector(0, 0);
this.acceleration = createVector(0, 0);
}
applyForce(force) {
let f = p5.Vector.div(force, this.mass);
this.acceleration.add(f);
}
update() {
this.velocity.add(this.acceleration);
this.position.add(this.velocity);
this.acceleration.mult(0);
}
display() {
stroke(0);
strokeWeight(2);
fill(127, 127);
ellipse(this.position.x, this.position.y, this.mass * 16);
}
attract(other) {
// Calculate direction of force
let force = p5.Vector.sub(this.position, other.position);
// Distance between objects
let distance = force.mag();
// Limiting the distance to eliminate "extreme" results for very close or very far objects
distance = constrain(distance, 5.0, 25.0);
// Calculate gravitional force magnitude
let strength = (G * this.mass * other.mass) / (distance * distance);
// Get force vector --> magnitude * direction
force.setMag(strength);
return force;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

View file

@ -0,0 +1,30 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
let movers = [];
let G = 1;
function setup() {
createCanvas(640, 240);
for (let i = 0; i < 10; i++) {
movers[i] = new Mover(random(width), random(height), random(0.1, 2));
}
}
function draw() {
background(255);
for (let i = 0; i < movers.length; i++) {
for (let j = 0; j < movers.length; j++) {
if (i !== j) {
let force = movers[j].attract(movers[i]);
movers[i].applyForce(force);
}
}
movers[i].update();
movers[i].display();
}
}

View file

@ -0,0 +1,7 @@
html, body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 195 KiB

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 1,015 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,015 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 173 KiB