@@ -308,7 +308,7 @@ Example 1.2: Bouncing Ball with V
It may not always be obvious when to directly access an object’s properties versus when to reference the object as a whole or use one of its methods. The goal of this chapter (and most of this book) is to help you distinguish between these scenarios by providing a variety of examples and use cases.
Exercise 1.1
-
Take one of the walker examples from Chapter 0 and convert it to use vectors.
+
Take one of the walker examples from Chapter 0 and convert it to use vectors.
Exercise 1.2
@@ -674,7 +674,7 @@
Motion with Vectors
Add the velocity to the position.
Draw the object at the position.
-
In the bouncing ball example, all this code happened within setup()
and draw()
. What I want to do now is move toward encapsulating all the logic for an object’s motion inside a class. This way, I can create a foundation for programming moving objects that I can easily reuse again and again. (See “The Random Walker Class” for a brief review of OOP basics.)
+
In the bouncing ball example, all this code happened within setup()
and draw()
. What I want to do now is move toward encapsulating all the logic for an object’s motion inside a class. This way, I can create a foundation for programming moving objects that I can easily reuse again and again. (See “The Random Walker Class” for a brief review of OOP basics.)
To start, I’m going to create a generic Mover
class that will describe a shape moving around the canvas. For that, I must consider the following two questions:
- What data does a mover have?
@@ -788,7 +788,7 @@ Example 1.7: Motion 101 (Velocity)
}
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
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/02_forces.html b/content/02_forces.html
index 30a94ce7..43f40134 100644
--- a/content/02_forces.html
+++ b/content/02_forces.html
@@ -1,4 +1,4 @@
-
+
Chapter 2. Forces
@@ -74,7 +74,7 @@ Weight vs. Mass
In the world of p5.js, what is mass anyway? Aren’t we dealing with pixels? Let’s start simple and say that in a pretend pixel world, all objects have a mass equal to 1. Anything divided by 1 equals itself, and so, in this simple world, we have this:
\vec{A} = \vec{F}
-I’ve effectively removed mass from the equation, making the acceleration of an object equal to force. This is great news. After all, Chapter 1 described acceleration as the key to controlling the movement of objects in a canvas. I said that the position changes according to the velocity, and the velocity according to acceleration. Acceleration seemed to be where it all began. Now you can see that force is truly where it all begins.
+I’ve effectively removed mass from the equation, making the acceleration of an object equal to force. This is great news. After all, Chapter 1 described acceleration as the key to controlling the movement of objects in a canvas. I said that the position changes according to the velocity, and the velocity according to acceleration. Acceleration seemed to be where it all began. Now you can see that force is truly where it all begins.
Let’s take the Mover
class, with position, velocity, and acceleration:
class Mover {
constructor() {
@@ -143,7 +143,7 @@ Factoring In Mass
Units of Measurement
Now that I’m introducing mass, it’s important to make a quick note about units of measurement. In the real world, things are measured in specific units: two objects are 3 meters apart, the baseball is moving at a rate of 90 miles per hour, or this bowling ball has a mass of 6 kilograms. Sometimes you do want to take real-world units into consideration. In this chapter, however, I’m going to stick with units of measurement in pixels (“These two circles are 100 pixels apart”) and frames of animation (“This circle is moving at a rate of 2 pixels per frame,” the aforementioned time step).
In the case of mass, p5.js doesn’t have any unit of measurement to use. How much mass is in any given pixel? You might enjoy inventing your own p5.js unit of mass to associate with those values, like “10 pixeloids” or “10 yurkles.”
- For demonstration purposes, I’ll tie mass to pixels (the larger a circle’s diameter, the larger the mass). This will allow me to visualize the mass of an object, albeit inaccurately. In the real world, size doesn’t indicate mass. A small metal ball could have a much higher mass than a large balloon because of its higher density. And for two circular objects with equal density, I’ll also note that mass should be tied to the formula for the area of a circle: \pi r^2. (This will be addressed in Exercise 2.11, and I’ll say more about \pi and circles in Chapter 3.)
+ For demonstration purposes, I’ll tie mass to pixels (the larger a circle’s diameter, the larger the mass). This will allow me to visualize the mass of an object, albeit inaccurately. In the real world, size doesn’t indicate mass. A small metal ball could have a much higher mass than a large balloon because of its higher density. And for two circular objects with equal density, I’ll also note that mass should be tied to the formula for the area of a circle: \pi r^2. (This will be addressed in Exercise 2.11, and I’ll say more about \pi and circles in Chapter 3.)
Mass is a scalar, not a vector, as it’s just one number describing the amount of matter in an object. I could get fancy and compute the area of a shape as its mass, but it’s simpler to begin by saying, “Hey, the mass of this object is . . . um, I dunno . . . how about 10?”
constructor() {
@@ -197,7 +197,7 @@ Units of Measurement
Let’s take a moment to recap what I’ve covered so far. I’ve defined what a force is (a vector), and I’ve shown how to apply a force to an object (divide it by mass and add it to the object’s acceleration vector). What’s missing? Well, I have yet to figure out how to calculate a force in the first place. Where do forces come from?
Exercise 2.2
-
You could write applyForce()
in another way, using the static method div()
instead of copy()
. Rewrite applyForce()
by using the static method. For help with this exercise, review static methods in “Static vs. Nonstatic Methods”.
+
You could write applyForce()
in another way, using the static method div()
instead of copy()
. Rewrite applyForce()
by using the static method. For help with this exercise, review static methods in “Static vs. Nonstatic Methods”.
applyForce(force) {
let f = p5.Vector.div(force, this.mass);
this.acceleration.add(f);
@@ -228,7 +228,7 @@ Example 2.1: Forces
mover.applyForce(wind);
}
Now I have two forces, pointing in different directions and with different magnitudes, both applied to the object mover
. I’m beginning to get somewhere. I’ve built a world, an environment with forces that act on objects!
-
Let’s look at what happens now when I add a second object with a variable mass. To do this, you’ll probably want to do a quick review of OOP. Again, I’m not covering all the basics of programming here (for that, you can check out any of the intro p5.js books or video tutorials listed in “The Coding Train Connection”). However, since the idea of creating a world filled with objects is fundamental to all the examples in this book, it’s worth taking a moment to walk through the steps of going from one object to many.
+
Let’s look at what happens now when I add a second object with a variable mass. To do this, you’ll probably want to do a quick review of OOP. Again, I’m not covering all the basics of programming here (for that, you can check out any of the intro p5.js books or video tutorials listed in “The Coding Train Connection”). However, since the idea of creating a world filled with objects is fundamental to all the examples in this book, it’s worth taking a moment to walk through the steps of going from one object to many.
This is where I left the Mover
class. Notice that it’s identical to the Mover
class created in Chapter 1, with two additions, mass
and a new applyForce()
method:
class Mover {
constructor() {
@@ -279,7 +279,7 @@ Example 2.1: Forces
}
}
-
Now that the class is written, I can create more than one Mover
object.
+
Now that the class is written, I can create more than one Mover
object:
let moverA = new Mover();
let moverB = new Mover();
@@ -371,7 +371,7 @@
Modeling a Force
Making up forces will actually get you quite far—after all, I just made up a pretty good approximation of Earth’s gravity. Ultimately, the world of p5.js is an orchestra of pixels, and you’re the conductor, so whatever you deem appropriate to be a force, well by golly, that’s the force it should be! Nevertheless, there may come a time when you find yourself wondering, “But how does it all really work?” That’s when modeling forces, instead of just making them up, enters the picture.
-
In a moment, I’m going to write out the formula for friction. This won’t be the first time you’ve seen a formula in this book; I just finished up the discussion of Newton’s second law, \vec{F} = M \times \vec{A} (or force equals mass times acceleration). You hopefully didn’t spend a lot of time worrying about that formula, because it’s just a few characters and symbols. Nevertheless, it’s a scary world out there. Just take a look at the equation for a normal distribution, which I covered (without presenting the formula) in “A Normal Distribution of Random Numbers”:
+
In a moment, I’m going to write out the formula for friction. This won’t be the first time you’ve seen a formula in this book; I just finished up the discussion of Newton’s second law, \vec{F} = M \times \vec{A} (or force equals mass times acceleration). You hopefully didn’t spend a lot of time worrying about that formula, because it’s just a few characters and symbols. Nevertheless, it’s a scary world out there. Just take a look at the equation for a normal distribution, which I covered (without presenting the formula) in “A Normal Distribution of Random Numbers”:
\frac{1}{\sigma\sqrt{2\pi}}e^{-\frac{(x-\mu)^2}{2\sigma^2}}
Formulas are regularly written with many symbols (often with letters from the Greek alphabet). Here’s the formula for friction (as indicated by \vec{f}):
\vec{f} = -\mu N \hat{v}
@@ -924,7 +924,7 @@
Example 2.7: Attraction with Man
movers[i].show();
}
}
-
This is just a small taste of what’s possible with arrays of objects. Stay tuned for a more in-depth exploration of adding and removing multiple objects from the canvas in Chapter 4, which covers particle systems.
+
This is just a small taste of what’s possible with arrays of objects. Stay tuned for a more in-depth exploration of adding and removing multiple objects from the canvas in Chapter 4, which covers particle systems.
Exercise 2.12
In Example 2.7, there’s a system (an array) of Mover
objects and one Attractor
object. Build an example that has systems of both movers and attractors. What if you make the attractors invisible? Can you create a pattern/design from the trails of objects moving around attractors?
@@ -1061,7 +1061,7 @@
Example 2.9: n Bodies
}
}
The nested loop solution in Example 2.9 leads to what’s called an n-squared algorithm, meaning the number of calculations is equal to the number of bodies squared. If I were to increase the number of bodies, the simulation would start to slow significantly because of the number of calculations required.
-
In Chapter 5, I’ll explore strategies for optimizing sketches like this one, with a particular focus on spatial subdivision algorithms. Spatial subdivision, in combination with the concept of quadtrees and an algorithm called Barnes-Hut, is particularly effective for improving efficiency in simulations such as the n-body one discussed here.
+
In Chapter 5, I’ll explore strategies for optimizing sketches like this one, with a particular focus on spatial subdivision algorithms. Spatial subdivision, in combination with the concept of quadtrees and an algorithm called Barnes-Hut, is particularly effective for improving efficiency in simulations such as the n-body one discussed here.
Exercise 2.15
Change the attraction force in Example 2.9 to a repulsion force. Can you create an example in which all the Body
objects are attracted to the mouse but repel one another? Think about how you need to balance the relative strength of the forces and how to most effectively use distance in your force calculations.
diff --git a/content/03_oscillation.html b/content/03_oscillation.html
index 7ff19010..4a667253 100644
--- a/content/03_oscillation.html
+++ b/content/03_oscillation.html
@@ -1,4 +1,4 @@
-
+
Chapter 3. Oscillation
@@ -16,9 +16,9 @@ Chapter 3. Oscillation
Gala by Bridget Riley, 1974; acrylic on canvas, 159.7 × 159.7 cm
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.
Angles
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).
Angular Motion
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?
\overrightarrow{\text{velocity}} = \overrightarrow{\text{velocity}} + \overrightarrow{\text{acceleration}}
\overrightarrow{\text{position}} = \overrightarrow{\text{position}} + \overrightarrow{\text{velocity}}
@@ -168,7 +168,7 @@
Exercise 3.2
At this point, if you were to actually go ahead and create a Mover
object, you wouldn’t see it behave any differently. This is because the angular acceleration is initialized to zero (this.angleAcceleration = 0;
). For the object to rotate, it needs a nonzero acceleration! Certainly, one option is to hardcode a number in the constructor:
this.angleAcceleration = 0.01;
-
You can produce a more interesting result, however, by dynamically assigning an angular acceleration in the update()
method according to forces in the environment. This could be my cue to start researching the physics of angular acceleration based on the concepts of torque and moment of inertia, but at this stage, that level of simulation would be a bit of a rabbit hole. (I’ll cover modeling angular acceleration with a pendulum in more detail in “The Pendulum”, as well as look at how third-party physics libraries realistically model rotational motion in Chapter 6.)
+
You can produce a more interesting result, however, by dynamically assigning an angular acceleration in the update()
method according to forces in the environment. This could be my cue to start researching the physics of angular acceleration based on the concepts of torque and moment of inertia, but at this stage, that level of simulation would be a bit of a rabbit hole. (I’ll cover modeling angular acceleration with a pendulum in more detail in “The Pendulum”, as well as look at how third-party physics libraries realistically model rotational motion in Chapter 6.)
Instead, a quick-and-dirty solution that yields creative results will suffice. A reasonable approach is to calculate angular acceleration as a function of the object’s linear acceleration, its rate of change of velocity along a path vector, as opposed to its rotation. Here’s an example:
// Use the x-component of the object’s linear acceleration to calculate angular acceleration.
this.angleAcceleration = this.acceleration.x;
@@ -487,7 +487,7 @@
Example 3.5: Simple Harmonic Motion
Exercise 3.7
-
Using the sine function, create a simulation of a weight (sometimes referred to as a bob) that hangs from a spring from the top of the window. Use the map()
function to calculate the vertical position of the bob. In “Spring Forces”, I’ll demonstrate how to create this same simulation by modeling the forces of a spring according to Hooke’s law.
+
Using the sine function, create a simulation of a weight (sometimes referred to as a bob) that hangs from a spring from the top of the window. Use the map()
function to calculate the vertical position of the bob. In “Spring Forces”, I’ll demonstrate how to create this same simulation by modeling the forces of a spring according to Hooke’s law.
Oscillation with Angular Velocity
An understanding of oscillation, amplitude, and period (or frequency) can be essential in the course of simulating real-world behaviors. However, there’s a slightly easier way to implement the simple harmonic motion from Example 3.5, one that achieves the same result with fewer variables. Take one more look at the oscillation formula:
@@ -495,7 +495,7 @@
Oscillation with Angular Velocity
Now I’ll rewrite it in a slightly different way:
let x = amplitude * sin( some value that increments slowly );
If you care about precisely defining the period of oscillation in terms of frames of animation, you might need the formula as I first wrote it. If you don’t care about the exact period, however—for example, if you’ll be choosing it randomly—all you really need inside the sin()
function is a value that increments slowly enough for the object’s motion to appear smooth from one frame to the next. Every time this value ticks past a multiple of 2\pi, the object will have completed one cycle of oscillation.
-
This technique mirrors what I did with Perlin noise in Chapter 0. In that case, I incremented an offset variable (which I called t
or xoff
) to sample various outputs from the noise()
function, creating a smooth transition of values. Now, I’m going to increment a value (I’ll call it angle
) that’s fed into the sin()
function. The difference is that the output from sin()
is a smoothly repeating sine wave, without any randomness.
+
This technique mirrors what I did with Perlin noise in Chapter 0. In that case, I incremented an offset variable (which I called t
or xoff
) to sample various outputs from the noise()
function, creating a smooth transition of values. Now, I’m going to increment a value (I’ll call it angle
) that’s fed into the sin()
function. The difference is that the output from sin()
is a smoothly repeating sine wave, without any randomness.
You might be wondering why I refer to the incrementing value as angle
, given that the object has no visible rotation. The term angle is used because the value is passed into the sin()
function, and angles are the traditional inputs to trigonometric functions. With this in mind, I can reintroduce the concept of angular velocity (and acceleration) to rewrite the example to calculate the x
position in terms of a changing angle. I’ll assume these global variables:
let angle = 0;
let angleVelocity = 0.05;
@@ -700,7 +700,7 @@
Spring Forces
Figure 3.14: A spring with an anchor and bob
-
Exploring the mathematics of triangles and waves has been lovely, but perhaps you’re starting to miss Newton’s laws of motion and vectors. After all, the core of this book is about simulating the physics of moving bodies. In “Properties of Oscillation”, I modeled simple harmonic motion by mapping a sine wave to a range of pixels on a canvas. Exercise 3.7 asked you to use this technique to create a simulation of a bob hanging from a spring with the sin()
function. That kind of quick-and-dirty, one-line-of-code solution won’t do, however, if what you really want is a bob hanging from a spring that responds to other forces in the environment (wind, gravity, and so on). To achieve a simulation like that, you need to model the force of the spring by using vectors.
+
Exploring the mathematics of triangles and waves has been lovely, but perhaps you’re starting to miss Newton’s laws of motion and vectors. After all, the core of this book is about simulating the physics of moving bodies. In “Properties of Oscillation”, I modeled simple harmonic motion by mapping a sine wave to a range of pixels on a canvas. Exercise 3.7 asked you to use this technique to create a simulation of a bob hanging from a spring with the sin()
function. That kind of quick-and-dirty, one-line-of-code solution won’t do, however, if what you really want is a bob hanging from a spring that responds to other forces in the environment (wind, gravity, and so on). To achieve a simulation like that, you need to model the force of the spring by using vectors.
I’ll consider a spring to be a connection between a movable bob (or weight) and a fixed anchor point (see Figure 3.14).