Merge pull request #865 from nature-of-code/notion-update-docs

[Notion] Update docs
This commit is contained in:
Daniel Shiffman 2024-02-26 20:41:20 -05:00 committed by GitHub
commit 30941a6334
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 19 additions and 30 deletions

View file

@ -278,9 +278,11 @@ if (mouseIsPressed) {
}
}
}</pre>
<p>Now that the class is written, I can create more than one <code>Mover</code> object.</p>
<pre class="codesplit" data-code-language="javascript">let moverA = new Mover();
<div class="avoid-break">
<p>Now that the class is written, I can create more than one <code>Mover</code> object.</p>
<pre class="codesplit" data-code-language="javascript">let moverA = new Mover();
let moverB = new Mover();</pre>
</div>
<p>But theres an issue. Look again at the <code>Mover</code> objects constructor:</p>
<pre class="codesplit" data-code-language="javascript">constructor() {
//{!2} Every object has a mass of 1 and a position of (width / 2, 30).
@ -791,10 +793,12 @@ mover.applyForce(force);</code></pre>
<pre class="codesplit" data-code-language="javascript">// Made-up force
let force = createVector(0, 0.1);
mover.applyForce(force);</pre>
<p>I now have this:</p>
<pre class="codesplit" data-code-language="javascript">//{!1} Attraction force between two objects
<div class="avoid-break">
<p>I now have this:</p>
<pre class="codesplit" data-code-language="javascript">//{!1} Attraction force between two objects
<strong>let force = attractor.attract(mover);</strong>
mover.applyForce(force);</pre>
</div>
<p>And so the <code>draw()</code> function can be written as shown here:</p>
<pre class="codesplit" data-code-language="javascript">function draw() {
background(255);
@ -1015,8 +1019,8 @@ function draw() {
}
}</pre>
<p>The <code>draw()</code> function is where I need to work some magic so that every body exerts a gravitational force on every other body. Right now, the code reads, “For every body <code>i</code>, update and draw.” To attract every other body <code>j</code> with each body <code>i</code>, I need to nest a second loop and adjust the code to say, “For every body <code>i</code>, attract every other body <code>j</code> (and update and draw).”</p>
<pre class="codesplit" data-code-language="javascript"> for (let i = 0; i &#x3C; bodies.length; i++) {
// For every body, check every body!
<pre class="codesplit" data-code-language="javascript"> //{!2} For every body, check every body!
for (let i = 0; i &#x3C; bodies.length; i++) {
for (let j = 0; j &#x3C; bodies.length; j++) {
let force = bodies[j].attract(bodies[i]);
movers[i].applyForce(force);

View file

@ -1084,7 +1084,7 @@ function setup() {
}
function draw() {
background(100);
background(255);
emitter.addParticle();
// Apply a universal gravity.
let gravity = createVector(0, 0.1);
@ -1092,7 +1092,6 @@ function draw() {
//{!1} Apply the repeller.
emitter.applyRepeller(repeller);
emitter.run();
repeller.show();
}

View file

@ -91,15 +91,13 @@
<p>While I encourage you to consider how other forces such as friction and drag could be combined with steering behaviors, Im going to focus only on steering forces for the time being. As such, I can include the concept of maximum speed as a limiting factor in the force calculation. First, I need to add a property to the <code>Vehicle</code> class setting the maximum speed:</p>
<div class="snip-below">
<pre class="codesplit" data-code-language="javascript">class Vehicle {
constructor() {
this.position = createVector();
this.velocity = createVector();
this.acceleration = createVector();
// Maximum speed
this.maxspeed = ????;
}
</pre>
}</pre>
</div>
<p>Then, in the desired velocity calculation, Ill scale according to maximum speed:</p>
<pre class="codesplit" data-code-language="javascript">let desired = p5.Vector.sub(target, this.position);
@ -126,7 +124,6 @@ desired.setMag(this.maxspeed);</pre>
<p>In all this excitement, Ive missed one last step. What sort of vehicle is this? Is it a super-sleek race car with amazing handling? Or a large city bus that needs a lot of advance notice to turn? A graceful panda or a lumbering elephant? The example code, as it stands, has no feature to account for this variation in steering ability. For that, I need to limit the magnitude of the steering force. Ill call this limit the maximum force (or <code>maxforce</code> for short):</p>
<div class="snip-below">
<pre class="codesplit" data-code-language="javascript">class Vehicle {
constructor() {
this.position = createVector();
this.velocity = createVector();
@ -143,10 +140,8 @@ desired.setMag(this.maxspeed);</pre>
let desired = p5.Vector.sub(target, this.position);
desired.setMag(this.maxspeed);
let steer = p5.Vector.sub(desired, this.velocity);
//{!1} Limit the magnitude of the steering force.
steer.limit(this.maxforce);
this.applyForce(steer);
}</pre>
</div>
@ -684,7 +679,7 @@ let angle = acos(a.dot(b) / (a.mag() * b.mag()));</pre>
this.end = createVector(width, (2 * height) / 3);
}
//{!7} Display the path.
//{!1} Display the path.
show() {
strokeWeight(this.radius * 2);
stroke(0, 100);
@ -702,10 +697,8 @@ let angle = acos(a.dot(b) / (a.mag() * b.mag()));</pre>
<p>The first step is to predict (assuming a constant velocity) where that vehicle will be in the future:</p>
<pre class="codesplit" data-code-language="javascript">// Start by making a copy of the velocity.
let future = vel.copy();
//{!2} Look 25 pixels ahead by setting the magnitude.
// Look 25 pixels ahead by setting the magnitude.
future.setMag(25);
// Add the vector to the position to find the future position.
future.add(this.position);</pre>
<p>Once I have that position, its time to determine the distance from that predicted position to the path. If its very far away, the vehicle has strayed from the path and needs to steer back toward it. If the vehicle is on the path, all is well and the vehicle can continue on its way.</p>
@ -745,12 +738,10 @@ let normalPoint = p5.Vector.add(path.start, b);</pre>
<p>Or, more simply:</p>
<div data-type="equation">\vec{A}\cdot\vec{B}=||\vec{A}||\times\cos(\theta)</div>
<p>When <span data-type="equation">\vec{B}</span> is a unit vector, <span data-type="equation">||\vec{A}|| \times \cos(\theta)</span> is the same as the dot product of <span data-type="equation">\vec{A}</span> and <span data-type="equation">\vec{B}</span>. Turning <code>b</code> into a unit vector is as simple as calling <code>normalize()</code>. I can therefore bypass calculating <code>theta</code> with <code>angleBetween()</code> and simplify the code as follows:</p>
<pre class="codesplit" data-code-language="javascript">//{{!3} .line-through}
let theta = p5.Vector.angleBetween(a, b);
<pre class="codesplit" data-code-language="javascript"><s>let theta = p5.Vector.angleBetween(a, b);
let d = a.mag() * cos(theta);
b.setMag(d);
// Normalize <code>b</code> and use the dot product to set <code>b</code>s length.
b.setMag(d);</s><s>
</s>//{!2} Normalize <code>b</code> and use the dot product to set <code>b</code>s length.
b.normalize();
b.setMag(a.dot(b));
let normalPoint = p5.Vector.add(path.start, b);</pre>
@ -1196,9 +1187,8 @@ function draw() {
let steer = p5.Vector.sub(desired, this.velocity);
steer.limit(this.maxforce);
//{!1 .line-through}
this.applyForce(steer);
//{!1} Instead of applying the force, return the vector.
<s>this.applyForce(steer);</s><s>
</s> //{!1} Instead of applying the force, return the vector.
return steer;
}</pre>
<p>This change is subtle but incredibly important: it allows the strength of these forces to be weighted all in one place.</p>
@ -1252,12 +1242,10 @@ function draw() {
let separation = this.separate(boids);
let alignment = this.align(boids);
let cohesion = this.cohere(boids);
//{!3} Arbitrary weights for these forces (try different ones!)
separation.mult(1.5);
alignment.mult(1.0);
cohesion.mult(1.0);
//{!3} Apply all the forces.
this.applyForce(separation);
this.applyForce(alignment);
@ -1272,10 +1260,8 @@ function draw() {
sum.add(other.velocity);
}
sum.div(boids.length);
// The vehicle desires to go in that direction at maximum speed.
sum.setMag(this.maxspeed);
//{!3} Reynoldss steering force formula
let steer = p5.Vector.sub(sum, this.velocity);
steer.limit(this.maxforce);