Notion - Update docs
|
@ -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), I’m 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>), I’m 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>Let’s 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. Let’s 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. Let’s 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, it’s important to understand that I haven’t 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 I’ll 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, it’s important to understand that the power of programming with vectors hasn’t 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 I’ll 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, there’s 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 < 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, let’s start with subtraction. This one’s 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, let’s 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 component’s 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 you’re 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 you’re 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. We’re 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. We’re 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, let’s 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 vector’s direction without regard to its length. You’ll 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>
|
||||
|
|
|
@ -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. Let’s say you are driving a car. When you press your foot down on the brake pedal, the car’s 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>It’s 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, that’s 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. Let’s look at the formula:</p>
|
||||
|
@ -495,7 +483,7 @@ friction.mult(frictionMag);
|
|||
</ul>
|
||||
<p>Now that I’ve 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, I’m ready to put it all together! In the following example, I‘ll 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 Newton‘s 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. I’ll do it in two parts. First, I’ll compute the direction of the force <span data-type="equation">\hat{r}</span> in the formula above. Second, I’ll 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 don’t 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. Didn’t I just make a vector that points all the way from one position to another? Wouldn’t 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 I’ll have the distance. And this time, I‘ll 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 I’ve worked out the math and code for calculating an attractive force (emulating gravity), let‘s 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. Let’s 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, it’s 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 hasn’t changed at all, so let’s 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, you’ll 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 creature’s 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>
|
||||
|
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 28 KiB |
|
@ -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);
|
||||
}
|
||||
|
|
After Width: | Height: | Size: 23 KiB |
|
@ -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);
|
||||
}
|
||||
|
|
After Width: | Height: | Size: 23 KiB |
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
BIN
content/examples/02_forces/example_2_1_forces/screenshot.png
Normal file
After Width: | Height: | Size: 188 KiB |
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
After Width: | Height: | Size: 66 KiB |
|
@ -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();
|
||||
}
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
After Width: | Height: | Size: 136 KiB |
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
canvas {
|
||||
display: block;
|
||||
}
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
After Width: | Height: | Size: 160 KiB |
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
canvas {
|
||||
display: block;
|
||||
}
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 28 KiB |
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
canvas {
|
||||
display: block;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
BIN
content/examples/02_forces/example_2_6_attraction/screenshot.png
Normal file
After Width: | Height: | Size: 36 KiB |
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
canvas {
|
||||
display: block;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 110 KiB |
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
canvas {
|
||||
display: block;
|
||||
}
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 83 KiB |
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
canvas {
|
||||
display: block;
|
||||
}
|
Before Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 195 KiB After Width: | Height: | Size: 3.2 MiB |
Before Width: | Height: | Size: 128 KiB |
Before Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 173 KiB |
Before Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 3.2 MiB |
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 1,015 KiB |
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 1.7 MiB |
Before Width: | Height: | Size: 1,015 KiB After Width: | Height: | Size: 108 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 195 KiB |
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 128 KiB |
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 158 KiB After Width: | Height: | Size: 173 KiB |