diff --git a/content/01_vectors.html b/content/01_vectors.html index d00b7bb7..38b56dea 100644 --- a/content/01_vectors.html +++ b/content/01_vectors.html @@ -795,7 +795,7 @@
If OOP is at all new to you, one aspect here may seem a bit strange. I spent the beginning of this chapter discussing the p5.Vector
class, and this class is the template for making the position
object and the velocity
object. So what are those objects doing inside yet another object, the Mover
object?
In fact, this is just about the most normal thing ever. An object is something that holds data (and functionality). That data can be numbers, or it can be other objects (arrays too)! You’ll see this over and over again in this book. In Chapter 4, for example, I’ll write a class to describe a system of particles. That ParticleSystem
object will include a list of Particle
objects . . . and each Particle
object will have as its data several p5.Vector
objects!
You may have also noticed in the Mover
class that I’m setting the initial position and velocity directly within the constructor, without using any arguments. While this approach keeps the code simple for now, I’ll explore the benefits of adding arguments to the constructor in Chapter 2.
You may have also noticed in the Mover
class that I’m setting the initial position and velocity directly within the constructor, without using any arguments. While this approach keeps the code simple for now, I’ll explore the benefits of adding arguments to the constructor in Chapter 2.
At this point, you hopefully feel comfortable with two concepts: (1) what a vector is and (2) how to use vectors inside an object to keep track of its position and movement. This is an excellent first step and deserves a mild round of applause. Before standing ovations are in order, however, you need to make one more, somewhat bigger step forward. After all, watching the Motion 101 example is fairly boring. The circle never speeds up, never slows down, and never turns. For more sophisticated motion—the kind of motion that appears in the world around us—one more vector needs to be added to the class: acceleration
.
Acceleration is the rate of change of velocity. Think about that definition for a moment. Is it a new concept? Not really. Earlier I defined velocity as the rate of change of position, so in essence I’m developing a trickle-down effect. Acceleration affects velocity, which in turn affects position. (To provide some brief foreshadowing, this point will become even more crucial in the next chapter, when I show how forces like friction affect acceleration, which affects velocity, which affects position.) In code, this trickle-down effect reads like this:
diff --git a/content/03_oscillation.html b/content/03_oscillation.html index 30062830..55ef9456 100644 --- a/content/03_oscillation.html +++ b/content/03_oscillation.html @@ -16,9 +16,9 @@Bridget Riley, a celebrated British artist, was a driving force behind the Op Art movement of the 1960s. Her work features geometric patterns that challenge the viewer’s perceptions and evoke feelings of movement or vibration. Her 1974 piece Gala showcases a series of curvilinear forms that ripple across the canvas, evoking the natural rhythm of the sine wave.
-In Chapters 1 and 2, I carefully worked out an object-oriented structure to animate a shape in a p5.js canvas, using a vector to represent position, velocity, and acceleration driven by forces in the environment. I could move straight from here into topics such as particle systems, steering forces, group behaviors, and more. However, doing so would mean skipping a fundamental aspect of motion in the natural world: oscillation, or the back-and-forth movement of an object around a central point or position.
+In Chapters 1 and 2, I carefully worked out an object-oriented structure to animate a shape in a p5.js canvas, using a vector to represent position, velocity, and acceleration driven by forces in the environment. I could move straight from here into topics such as particle systems, steering forces, group behaviors, and more. However, doing so would mean skipping a fundamental aspect of motion in the natural world: oscillation, or the back-and-forth movement of an object around a central point or position.
To model oscillation, you need to understand a little bit about trigonometry, the mathematics of triangles. Learning some trig will give you new tools to generate patterns and create new motion behaviors in a p5.js sketch. You’ll learn to harness angular velocity and acceleration to spin objects as they move. You’ll be able to use the sine and cosine functions to model nice ease-in, ease-out wave patterns. You’ll also learn to calculate the more complex forces at play in situations that involve angles, such as a pendulum swinging or a box sliding down an incline.
-I’ll start with the basics of working with angles in p5.js, then cover several aspects of trigonometry. In the end, I’ll connect trigonometry with what you learned about forces in Chapter 2. This chapter’s content will pave the way for more sophisticated examples that require trig later in this book.
+I’ll start with the basics of working with angles in p5.js, then cover several aspects of trigonometry. In the end, I’ll connect trigonometry with what you learned about forces in Chapter 2. This chapter’s content will pave the way for more sophisticated examples that require trig later in this book.
Before going any further, I need to make sure you understand how the concept of an angle fits into creative coding in p5.js. If you have experience with p5.js, you’ve undoubtedly encountered this issue while using the rotate()
function to rotate and spin objects.
You’re most likely to be familiar with the concept of an angle as measured in degrees (see Figure 3.1). A full rotation goes from 0 to 360 degrees, and 90 degrees (a right angle) is one-fourth of 360, shown in Figure 3.1 as two perpendicular lines.
@@ -63,7 +63,7 @@Another term for rotation is angular motion—that is, motion about an angle. Just as linear motion can be described in terms of velocity—the rate at which an object’s position changes over time—angular motion can be described in terms of angular velocity—the rate at which an object’s angle changes over time. By extension, angular acceleration describes changes in an object’s angular velocity.
-Luckily, you already have all the math you need to understand angular motion. Remember the stuff I dedicated almost all of Chapters 1 and 2 to explaining?
+Luckily, you already have all the math you need to understand angular motion. Remember the stuff I dedicated almost all of Chapters 1 and 2 to explaining?
You can apply exactly the same logic to a rotating object:
@@ -734,7 +734,7 @@I’ll then use Hooke’s law to calculate the magnitude of the force. For that, I need k
and x
. Calculating k
is easy; it’s just a constant, so I’ll make something up:
let k = 0.1;-
Finding x
is perhaps a bit more difficult. I need to know the difference between the current length and the rest length. The rest length is defined as the variable restLength
. What’s the current length? The distance between the anchor and the bob. And how can I calculate that distance? How about the magnitude of a vector that points from the anchor to the bob? (Note that this is exactly the same process I employed to find the distance between objects for the purposes of calculating gravitational attraction in Chapter 2.)
Finding x
is perhaps a bit more difficult. I need to know the difference between the current length and the rest length. The rest length is defined as the variable restLength
. What’s the current length? The distance between the anchor and the bob. And how can I calculate that distance? How about the magnitude of a vector that points from the anchor to the bob? (Note that this is exactly the same process I employed to find the distance between objects for the purposes of calculating gravitational attraction in Chapter 2.)
//{!1} A vector pointing from the anchor to the bob gives you the current length of the spring. let dir = p5.Vector.sub(bob, anchor); let currentLength = dir.mag(); @@ -800,7 +800,7 @@-Spring Forces
bob.show(); spring.show(); }
Think about how this compares to my first stab at gravitational attraction in Example 2.6, when I had separate Mover
and Attractor
classes. There, I wrote something like this:
Think about how this compares to my first stab at gravitational attraction in Example 2.6, when I had separate Mover
and Attractor
classes. There, I wrote something like this:
let force = attractor.attract(mover); mover.applyForce(force);
The analogous situation with a spring might have been as follows:
@@ -997,7 +997,7 @@Finally, a real-world pendulum is going to experience a certain amount of friction (at the pivot point) and air resistance. As it stands, the pendulum would swing forever with the given code. To make it more realistic, I can slow the pendulum with a damping trick. I say trick because rather than model the resistance forces with some degree of accuracy (as I did in Chapter 2), I can achieve a similar result simply by reducing the angular velocity by an arbitrary amount during each cycle. The following code reduces the velocity by 1 percent (or multiplies it by 0.99) for each frame of animation:
+Finally, a real-world pendulum is going to experience a certain amount of friction (at the pivot point) and air resistance. As it stands, the pendulum would swing forever with the given code. To make it more realistic, I can slow the pendulum with a damping trick. I say trick because rather than model the resistance forces with some degree of accuracy (as I did in Chapter 2), I can achieve a similar result simply by reducing the angular velocity by an arbitrary amount during each cycle. The following code reduces the velocity by 1 percent (or multiplies it by 0.99) for each frame of animation:
this.angleVelocity *= 0.99;
Putting everything together, I have the following example (with the pendulum beginning at a 45-degree angle).
Take one of your creatures and incorporate oscillation into its motion. You can use the Oscillator
class from Example 3.7 as a model. The Oscillator
object, however, oscillates around a single point (the middle of the window). Try oscillating around a moving point.
In other words, design a creature that moves around the screen according to position, velocity, and acceleration. But that creature isn’t just a static shape; it’s an oscillating body. Consider tying the speed of oscillation to the speed of motion. Think of a butterfly’s flapping wings or the legs of an insect. Can you make it appear as though the creature’s internal mechanics (oscillation) drive its locomotion? See the book’s website for an additional example combining attraction from Chapter 2 with oscillation.
+In other words, design a creature that moves around the screen according to position, velocity, and acceleration. But that creature isn’t just a static shape; it’s an oscillating body. Consider tying the speed of oscillation to the speed of motion. Think of a butterfly’s flapping wings or the legs of an insect. Can you make it appear as though the creature’s internal mechanics (oscillation) drive its locomotion? See the book’s website for an additional example combining attraction from Chapter 2 with oscillation.
-The vehicle’s goal and subsequent action is to seek the target. Thinking back to Chapter 2, you might begin by making the target an attractor and applying a gravitational force that pulls the vehicle to the target. This would be a perfectly reasonable solution, but conceptually it’s not what I’m looking for here.
+The vehicle’s goal and subsequent action is to seek the target. Thinking back to Chapter 2, you might begin by making the target an attractor and applying a gravitational force that pulls the vehicle to the target. This would be a perfectly reasonable solution, but conceptually it’s not what I’m looking for here.
I don’t want to simply calculate a force that pushes the vehicle toward its target; rather, I want to ask the vehicle to make an intelligent decision to steer toward the target based on its perception of its own state (its speed and the direction in which it’s currently moving) and its environment (the location of the target). The vehicle should consider how it desires to move (a vector pointing to the target), compare that goal with how it’s currently moving (its velocity), and apply a force accordingly. That’s exactly what Reynolds’s steering force formula says:
Or, as you might write in p5.js:
@@ -111,7 +111,7 @@Notice that I finish the method by passing the steering force into applyForce()
. This assumes that the code is built on top of the foundation I developed in Chapter 2.
Notice that I finish the method by passing the steering force into applyForce()
. This assumes that the code is built on top of the foundation I developed in Chapter 2.
To see why Reynolds’s steering formula works so well, take a look at Figure 5.4. It shows what the steering force looks like relative to the vehicle and target positions.
-Here’s the full Vehicle
class, incorporating the rest of the elements from the Chapter 2 Mover
class.
Here’s the full Vehicle
class, incorporating the rest of the elements from the Chapter 2 Mover
class.
The most exciting and intriguing group behaviors come from mixing and matching multiple steering forces. After all, how could I even begin to simulate emergence in a complex system through a sketch that has only one rule?
-When multiple steering forces are at play, I need a mechanism for managing them all. You may be thinking, “This is nothing new. We juggle multiple forces all the time.” You would be right. In fact, this technique appeared as early as Chapter 2:
+When multiple steering forces are at play, I need a mechanism for managing them all. You may be thinking, “This is nothing new. We juggle multiple forces all the time.” You would be right. In fact, this technique appeared as early as Chapter 2:
let wind = createVector(0.001, 0); let gravity = createVector(0, 0.1); mover.applyForce(wind); @@ -1493,7 +1493,7 @@Example 5.13: Quadtree
The quadtree data structure is key to the Barnes-Hut algorithm, which I referenced briefly when building an n-body simulation in Chapter 2. This method uses a quadtree to approximate groups of bodies into a single one when calculating gravitational forces. This drastically reduces the number of calculations needed, allowing simulations with large numbers of bodies to run more efficiently. You can learn more about building a quadtree and applying it to a flocking system as part of Coding Challenge #98 on the Coding Train website.
+The quadtree data structure is key to the Barnes-Hut algorithm, which I referenced briefly when building an n-body simulation in Chapter 2. This method uses a quadtree to approximate groups of bodies into a single one when calculating gravitational forces. This drastically reduces the number of calculations needed, allowing simulations with large numbers of bodies to run more efficiently. You can learn more about building a quadtree and applying it to a flocking system as part of Coding Challenge #98 on the Coding Train website.
Expand the bin-lattice spatial subdivision flocking sketch from Example 5.12 to use a quadtree.
diff --git a/content/06_libraries.html b/content/06_libraries.html index 51dfecdb..3f36e684 100644 --- a/content/06_libraries.html +++ b/content/06_libraries.html @@ -899,12 +899,12 @@In this example, you’ll see that the stiffness
property of the constraint is set to 0.7
, giving a bit of elasticity to the imaginary mouse string. Other properties such as angularStiffness
and damping
can also influence the mouse’s interaction. Play around with these values. What happens if you adjust the stiffness?
In Chapter 2, I covered how to build an environment with multiple forces at play. An object might respond to gravitational attraction, wind, air resistance, and so on. Clearly, forces are at work in Matter.js as rectangles and circles spin and fly around the screen! But so far, I’ve demonstrated how to manipulate only a single global force: gravity.
+In Chapter 2, I covered how to build an environment with multiple forces at play. An object might respond to gravitational attraction, wind, air resistance, and so on. Clearly, forces are at work in Matter.js as rectangles and circles spin and fly around the screen! But so far, I’ve demonstrated how to manipulate only a single global force: gravity.
let engine = Engine.create(); // Change the engine’s gravity to point horizontally. engine.gravity.x = 1; engine.gravity.y = 0;-
If I want to use any of the Chapter 2 techniques with Matter.js, I need look no further than the trusty applyForce()
method. In Chapter 2, I wrote this method as part of the Mover
class. It received a vector, divided it by mass, and accumulated it into the mover’s acceleration. With Matter.js, the same method exists, so I no longer need to write all the details myself! I can call it with the static Body.applyForce()
. Here’s what that looks like in what’s now the Box
class:
If I want to use any of the Chapter 2 techniques with Matter.js, I need look no further than the trusty applyForce()
method. In Chapter 2, I wrote this method as part of the Mover
class. It received a vector, divided it by mass, and accumulated it into the mover’s acceleration. With Matter.js, the same method exists, so I no longer need to write all the details myself! I can call it with the static Body.applyForce()
. Here’s what that looks like in what’s now the Box
class:
class Box { applyForce(force) { @@ -912,7 +912,7 @@-Adding More Forces
Body.applyForce(this.body, this.body.position, force); } }
Here, the Box
class’s applyForce()
method receives a force vector and simply passes it along to Matter.js’s applyForce()
method to apply it to the corresponding body. The key difference with this approach is that Matter.js is a more sophisticated engine than the examples from Chapter 2. The earlier examples assumed that the force was always applied at the mover’s center. Here, I’ve specified the exact position on the body where the force is applied. In this case, I’ve just applied it to the center as before by asking the body for its position, but this could be adjusted—for example, a force pushing at the edge of a box, causing it to spin across the canvas, much like dice tumbling when thrown.
Here, the Box
class’s applyForce()
method receives a force vector and simply passes it along to Matter.js’s applyForce()
method to apply it to the corresponding body. The key difference with this approach is that Matter.js is a more sophisticated engine than the examples from Chapter 2. The earlier examples assumed that the force was always applied at the mover’s center. Here, I’ve specified the exact position on the body where the force is applied. In this case, I’ve just applied it to the center as before by asking the body for its position, but this could be adjusted—for example, a force pushing at the edge of a box, causing it to spin across the canvas, much like dice tumbling when thrown.
How can I bring forces into a Matter.js-driven sketch? Say I want to use a gravitational attraction force. Remember the code from Example 2.6 in the Attractor
class?
attract(mover) { let force = p5.Vector.sub(this.position, mover.position); @@ -955,7 +955,7 @@-Example 6.9: Attraction with Matter return force; } }
In addition to writing a custom attract()
method for Example 6.9, two other key elements are required for the sketch to behave more like the example from Chapter 2. First, remember that a Matter.js Engine
has a default gravity pointing down. I need to disable it in setup()
with a (0, 0)
vector:
In addition to writing a custom attract()
method for Example 6.9, two other key elements are required for the sketch to behave more like the example from Chapter 2. First, remember that a Matter.js Engine
has a default gravity pointing down. I need to disable it in setup()
with a (0, 0)
vector:
engine = Engine.create(); //{!1} Disable the default gravity. engine.gravity = Vector.create(0, 0);@@ -1745,7 +1745,7 @@
I can now remake the attraction example from Chapter 2 with a single Attractor
object that exerts an attraction behavior anywhere on the canvas. Even though the attractor is centered, I’m using a distance threshold of the full width
to account for any movement of the attractor, and for particles located outside the canvas boundaries.
I can now remake the attraction example from Chapter 2 with a single Attractor
object that exerts an attraction behavior anywhere on the canvas. Even though the attractor is centered, I’m using a distance threshold of the full width
to account for any movement of the attractor, and for particles located outside the canvas boundaries.
In this section, I’m going to evolve my own simplified smart rockets, inspired by Thorp’s. When I get to the end of the section, I’ll leave implementing some of Thorp’s additional advanced features as an exercise.
My rockets will have only one thruster, which will be able to fire in any direction with any strength for every frame of animation. This isn’t particularly realistic, but it will make building out the example a little easier. (You can always make the rocket and its thrusters more advanced and realistic later.)
To implement my evolving smart rockets, I’ll start by taking the Mover
class from Chapter 2 and renaming it Rocket
:
To implement my evolving smart rockets, I’ll start by taking the Mover
class from Chapter 2 and renaming it Rocket
:
class Rocket { constructor(x, y) { // A rocket has three vectors: position, velocity, and acceleration. diff --git a/content/content.json b/content/content.json index 75bcfac6..b5ae0eac 100644 --- a/content/content.json +++ b/content/content.json @@ -1 +1 @@ -[{"title":"Dedication","type":"page","src":"./00_2_dedication.html","slug":"dedication"},{"title":"Acknowledgments","type":"page","src":"./00_4_acknowledgments.html","slug":"acknowledgements"},{"title":"Introduction","type":"page","src":"./00_5_introduction.html","slug":"introduction"},{"title":"0. Randomness","type":"chapter","src":"./00_randomness.html","slug":"random"},{"title":"1. Vectors","type":"chapter","src":"./01_vectors.html","slug":"vectors"},{"title":"2. Forces","type":"chapter","src":"./02_forces.html","slug":"force"},{"title":"3. Oscillation","type":"chapter","src":"./03_oscillation.html","slug":"oscillation"},{"title":"4. Particle Systems","type":"chapter","src":"./04_particles.html","slug":"particles"},{"title":"5. Autonomous Agents","type":"chapter","src":"./05_steering.html","slug":"autonomous-agents"},{"title":"6. Physics Libraries","type":"chapter","src":"./06_libraries.html","slug":"physics-libraries"},{"title":"7. Cellular Automata","type":"chapter","src":"./07_ca.html","slug":"cellular-automata"},{"title":"8. Fractals","type":"chapter","src":"./08_fractals.html","slug":"fractals"},{"title":"9. Evolutionary Computing","type":"chapter","src":"./09_ga.html","slug":"genetic-algorithms"},{"title":"10. Neural Networks","type":"chapter","src":"./10_nn.html","slug":"neural-networks"},{"title":"11. Neuroevolution","type":"chapter","src":"./11_nn_ga.html","slug":"neuroevolution"},{"title":"Appendix: Creature Design ","type":"page","src":"./xx_1_creature_design.html","slug":"appendix-creature"}] \ No newline at end of file +[{"title":"Dedication","type":"page","src":"./00_2_dedication.html","slug":"dedication"},{"title":"Acknowledgments","type":"page","src":"./00_4_acknowledgments.html","slug":"acknowledgements"},{"title":"Introduction","type":"page","src":"./00_5_introduction.html","slug":"introduction"},{"title":"0. Randomness","type":"chapter","src":"./00_randomness.html","slug":"random"},{"title":"1. Vectors","type":"chapter","src":"./01_vectors.html","slug":"vectors"},{"title":"2. Forces","type":"chapter","src":"./02_forces.html","slug":"forces"},{"title":"3. Oscillation","type":"chapter","src":"./03_oscillation.html","slug":"oscillation"},{"title":"4. Particle Systems","type":"chapter","src":"./04_particles.html","slug":"particles"},{"title":"5. Autonomous Agents","type":"chapter","src":"./05_steering.html","slug":"autonomous-agents"},{"title":"6. Physics Libraries","type":"chapter","src":"./06_libraries.html","slug":"physics-libraries"},{"title":"7. Cellular Automata","type":"chapter","src":"./07_ca.html","slug":"cellular-automata"},{"title":"8. Fractals","type":"chapter","src":"./08_fractals.html","slug":"fractals"},{"title":"9. Evolutionary Computing","type":"chapter","src":"./09_ga.html","slug":"genetic-algorithms"},{"title":"10. Neural Networks","type":"chapter","src":"./10_nn.html","slug":"neural-networks"},{"title":"11. Neuroevolution","type":"chapter","src":"./11_nn_ga.html","slug":"neuroevolution"},{"title":"Appendix: Creature Design ","type":"page","src":"./xx_1_creature_design.html","slug":"appendix-creature"}] \ No newline at end of file