mirror of
https://github.com/nature-of-code/noc-book-2
synced 2024-11-17 07:49:05 +01:00
Merge pull request #865 from nature-of-code/notion-update-docs
[Notion] Update docs
This commit is contained in:
commit
30941a6334
3 changed files with 19 additions and 30 deletions
|
@ -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 there’s an issue. Look again at the <code>Mover</code> object’s 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 < 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 < bodies.length; i++) {
|
||||
for (let j = 0; j < bodies.length; j++) {
|
||||
let force = bodies[j].attract(bodies[i]);
|
||||
movers[i].applyForce(force);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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, I’m 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, I’ll 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, I’ve 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. I’ll 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, it’s time to determine the distance from that predicted position to the path. If it’s 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} Reynolds’s steering force formula
|
||||
let steer = p5.Vector.sub(sum, this.velocity);
|
||||
steer.limit(this.maxforce);
|
||||
|
|
Loading…
Reference in a new issue