diff --git a/content/00_randomness.html b/content/00_randomness.html index dbcb6eb9..e4617156 100644 --- a/content/00_randomness.html +++ b/content/00_randomness.html @@ -156,13 +156,15 @@

Example 0.1: A Traditional Random this.y += ystep; }

Taking this further, I could get rid of floor() and use the random() function’s original floating-point numbers to create a continuous range of possible step lengths from –1 to 1:

-
  step() {
+
+
  step() {
     //{!2} Any floating-point number from –1 to 1
     let xstep = random(–1, 1);
     let ystep = random(–1, 1);
     this.x += xstep;
     this.y += ystep;
   }
+

All of these variations on the traditional random walk have one thing in common: at any moment in time, the probability that the walker will take a step in a given direction is equal to the probability that the walker will take a step in any other direction. In other words, if there are four possible steps, there is a 1 in 4 (or 25 percent) chance the walker will take any given step. With nine possible steps, it’s a 1 in 9 chance (about 11.1 percent).

Conveniently, this is how the random() function works. p5.js’s random-number generator (which operates behind the scenes) produces a uniform distribution of numbers. You can test this distribution by counting each time a random number is picked and graphing those values.

@@ -248,7 +250,8 @@

Exercise 0.2

  • From 0.6 to 0.7 (10 percent) → Dancing
  • From 0.7 to 1.0 (30 percent) → Sleeping
  • -
    let num = random(1);
    +
    +
    let num = random(1);
     
     // If the random number is less than 0.6
     if (num < 0.6) {
    @@ -260,6 +263,7 @@ 

    Exercise 0.2

    } else { print("Sleep!"); }
    +

    Now let’s apply this methodology to the random walker so it tends to move in a particular direction. Here’s an example of a Walker object with the following probabilities:

    • Chance of moving up: 20 percent
    • diff --git a/content/02_forces.html b/content/02_forces.html index 3b03b90f..f1c4ede6 100644 --- a/content/02_forces.html +++ b/content/02_forces.html @@ -380,16 +380,18 @@

      Parsing Formulas

    Open up any high school physics textbook and you’ll find diagrams and formulas describing various forces—gravity, electromagnetism, friction, tension, elasticity, and more. For the rest of this chapter, I’m going to consider three forces—friction, drag, and gravitational attraction—and show how to model them with p5.js. The point I’d like to make here is not that these are fundamental forces that you always need in your simulations. Rather, I want to demonstrate these forces as case studies for the following process:

    -
      -
    1. Understanding the concept behind a force
    2. -
    3. Deconstructing the force’s formula into two parts: -
        -
      1. How do you compute the force’s direction?
      2. -
      3. How do you compute the force’s magnitude?
      4. -
      -
    4. -
    5. Translating that formula into p5.js code that calculates a vector to be passed through a Mover object’s applyForce() method
    6. -
    +
    +
      +
    1. Understanding the concept behind a force
    2. +
    3. Deconstructing the force’s formula into two parts: +
        +
      1. How do you compute the force’s direction?
      2. +
      3. How do you compute the force’s magnitude?
      4. +
      +
    4. +
    5. Translating that formula into p5.js code that calculates a vector to be passed through a Mover object’s applyForce() method
    6. +
    +

    If you can follow these steps with the example forces I’ll provide here, then hopefully when you find yourself googling atomic nuclei weak nuclear force at 3 AM, you’ll have the skills to take what you find and adapt it for p5.js.

    Friction

    Let’s begin with friction and follow the preceding steps. Whenever two surfaces come into contact, they experience friction. Friction is a dissipative force, meaning it causes the kinetic energy of an object to be converted into another form, giving the impression of loss, or dissipation.

    diff --git a/content/03_oscillation.html b/content/03_oscillation.html index d6182e14..2d27b1c8 100644 --- a/content/03_oscillation.html +++ b/content/03_oscillation.html @@ -40,12 +40,12 @@

    Angles

    The catch is that, by default, p5.js measures angles not in degrees but in radians. This alternative unit of measurement is defined by the ratio of the length of the arc of a circle (a segment of the circle’s circumference) to the radius of that circle. One radian is the angle at which that ratio equals 1 (see Figure 3.3). A full circle (360 degrees) is equivalent to 2\pi radians, 180 degrees is equivalent to \pi radians, and 90 degrees is equivalent to \pi/2 radians.

    +

    The formula to convert from degrees to radians is as follows:

    +
    \text{radians} = {2\pi \times \text{degrees} \over 360}

    What Is Pi?

    The mathematical constant pi (or the Greek letter \pi) is a real number defined as the ratio of a circle’s circumference (the distance around the outside of the circle) to its diameter (a straight line that passes through the circle’s center). It’s equal to approximately 3.14159 and can be accessed in p5.js with the built-in PI variable.

    -

    The formula to convert from degrees to radians is as follows:

    -
    \text{radians} = {2\pi \times \text{degrees} \over 360}

    Thankfully, if you prefer to think of angles in degrees, you can call angleMode(DEGREES), or you can use the convenience function radians() to convert values from degrees to radians. The constants PI, TWO_PI, and HALF_PI are also available (equivalent to 180, 360, and 90 degrees, respectively). For example, here are two ways in p5.js to rotate a shape by 60 degrees:

    let angle = 60;
     rotate(radians(angle));
    diff --git a/content/06_libraries.html b/content/06_libraries.html
    index 86cbbf8f..8105ceae 100644
    --- a/content/06_libraries.html
    +++ b/content/06_libraries.html
    @@ -28,7 +28,7 @@ 

    Living root bridges (

    These activities have yielded a set of motion simulations, allowing you to creatively define the physics of the worlds you build (whether realistic or fantastical). But, of course, you and I aren’t the first or only people to do this. The world of computer graphics and programming is full of prewritten code libraries dedicated to physics simulations.

    Just try searching open source physics engine and you could spend the rest of your day poring over a host of rich and complex codebases. This begs the question: If an existing code library takes care of physics simulation, why should you bother learning how to write any of the algorithms yourself? Here’s where the philosophy behind this book comes into play. While many libraries provide out-of-the-box physics to experiment with (super-awesome, sophisticated, and robust physics at that), there are several good reasons for learning the fundamentals from scratch before diving into such libraries.

    First, without an understanding of vectors, forces, and trigonometry, it’s easy to get lost just reading the documentation of a library, let alone using it. Second, even though a library may take care of the math behind the scenes, it won’t necessarily simplify your code. A great deal of overhead may be required in understanding how a library works and what it expects from you code-wise. Finally, as wonderful as a physics engine might be, if you look deep down into your heart, you’ll likely see that you seek to create worlds and visualizations that stretch the limits of the imagination. A library may be great, but it provides only a limited set of features. It’s important to know when to live within those limitations in the pursuit of a creative coding project and when those limits will prove to be confining.

    -

    This chapter is dedicated to examining two open source physics libraries for JavaScript: Matter.js and Toxiclibs.js. I don’t mean to imply that these are the only libraries you should use for any and all creative coding projects that could benefit from a physics engine (see “Other Physics Libraries” for alternatives, and check the book’s website for ports of the chapter’s examples to other libraries). However, both libraries integrate nicely with p5.js and will allow me to demonstrate the fundamental concepts behind physics engines and how they relate to and build upon the material I’ve covered so far.

    +

    This chapter is dedicated to examining two open source physics libraries for JavaScript: Matter.js and Toxiclibs.js. I don’t mean to imply that these are the only libraries you should use for any and all creative coding projects that could benefit from a physics engine (see “Other Physics Libraries” for alternatives, and check the book’s website for ports of the chapter’s examples to other libraries). However, both libraries integrate nicely with p5.js and will allow me to demonstrate the fundamental concepts behind physics engines and how they relate to and build upon the material I’ve covered so far.

    Ultimately, the aim of this chapter isn’t to teach you the details of a specific physics library, but to provide you with a foundation for working with any physics library. The skills you acquire here will enable you to navigate and understand documentation, opening the door for you to expand your abilities with any library you choose.

    Why Use a Physics Library?

    I’ve made the case for writing your own physics simulations (as you’ve learned to do in the previous chapters), but why use a physics library? After all, adding any external framework or library to a project introduces complexity and extra code. Is that additional overhead worth it? If you just want to simulate a circle falling down because of gravity, for example, do you really need to import an entire physics engine and learn its API? As the early chapters of this book hopefully demonstrated, probably not. Lots of scenarios like this are simple enough for you to get by writing the code yourself.

    @@ -46,13 +46,15 @@

    Why Use a Physics Library?

    That’s easy enough, but how about calculating the circles’ velocities after the collision? This is where I’m going to stop the discussion. Why, you ask? It’s not that understanding the math behind collisions isn’t important or valuable. (In fact, I’m including additional examples on the website related to collisions without a physics library.) The reason for stopping is that life is short! (Let this also be a reason for you to consider going outside and frolicking for a bit before sitting down to write your next sketch.) You can’t expect to master every detail of physics simulation. And while you might enjoy learning about collision resolution for circles, it’s only going to make you want to work with rectangles next. And then with strangely shaped polygons. And then curved surfaces. And then swinging pendulums colliding with springy springs. And then, and then, and then . . .

    Incorporating complex features like collisions into a p5.js sketch while still having time to spend with friends and family—that’s the reason for this chapter. People have spent years developing solutions to these kinds of problems, and beautiful JavaScript libraries like Matter.js and Toxiclibs.js are the fruits of those efforts. You don’t need to reinvent the proverbial wheel, at least for now.

    In conclusion, if you find yourself describing an idea for a p5.js sketch and the word collisions comes up, then it’s likely time to learn to use a physics engine.

    -
    -

    allow-break Other Physics Libraries

    -

    A multitude of other physics libraries are worth exploring alongside this chapter’s two case studies, each with unique strengths that may offer advantages in certain kinds of projects. In fact, when I first began writing this book, Matter.js didn’t exist, so the physics engine I initially used to demonstrate the examples was Box2D. It was (and likely still is) the most well-known physics engine of them all.

    -

    Box2D began as a set of physics tutorials written in C++ by Erin Catto for the Game Developers Conference in 2006. Since then, Box2D has evolved into a rich and elaborate open source physics engine. It’s been used for countless projects, most notably highly successful games such as the award-winning Crayon Physics and the runaway hit Angry Birds.

    -

    One important feature of Box2D is that it’s a true physics engine: it knows nothing about computer graphics and the world of pixels, and instead does all its measurements and calculations in real-world units like meters, kilograms, and seconds. It’s just that its “world” (a key term in Box2D) is a 2D plane with top, bottom, left, and right edges. You tell it things like “The gravity of the world is 9.81 newtons per kilogram, and a circle with a radius of 4 meters and a mass of 50 kilograms is located 10 meters above the world’s bottom.” Box2D will then tell you things like “One second later, the rectangle is at 5 meters from the bottom; two seconds later, it’s 10 meters below,” and so on.

    -

    While this provides for an amazingly accurate and robust physics engine (one that’s highly optimized and fast for C++ projects), it also necessitates lots of complicated code to translate back and forth between Box2D’s physics world and the world you want to draw—the pixel world of the graphics canvas. This creates a tremendous burden for the coder. I will, as best I can, continue to maintain a set of Box2D-compatible examples for this book (there are several JavaScript ports), but I believe the relative simplicity of working with a library like Matter.js that is native to JavaScript and uses pixels as the unit of measurement will make for a more intuitive and friendly bridge from my p5.js examples.

    -

    Another notable library is p5play, a project initiated by Paolo Pedercini and currently led by Quinton Ashley that was specifically designed for game development. It simplifies the creation of visual objects—known as sprites—and manages their interactions (namely, collisions and overlaps). As you may have guessed from the name, p5play is tailored to work seamlessly with p5.js. It uses Box2D under the hood for physics simulation.

    +
    +
    +

    Other Physics Libraries

    +

    A multitude of other physics libraries are worth exploring alongside this chapter’s two case studies, each with unique strengths that may offer advantages in certain kinds of projects. In fact, when I first began writing this book, Matter.js didn’t exist, so the physics engine I initially used to demonstrate the examples was Box2D. It was (and likely still is) the most well-known physics engine of them all.

    +

    Box2D began as a set of physics tutorials written in C++ by Erin Catto for the Game Developers Conference in 2006. Since then, Box2D has evolved into a rich and elaborate open source physics engine. It’s been used for countless projects, most notably highly successful games such as the award-winning Crayon Physics and the runaway hit Angry Birds.

    +

    One important feature of Box2D is that it’s a true physics engine: it knows nothing about computer graphics and the world of pixels, and instead does all its measurements and calculations in real-world units like meters, kilograms, and seconds. It’s just that its “world” (a key term in Box2D) is a 2D plane with top, bottom, left, and right edges. You tell it things like “The gravity of the world is 9.81 newtons per kilogram, and a circle with a radius of 4 meters and a mass of 50 kilograms is located 10 meters above the world’s bottom.” Box2D will then tell you things like “One second later, the rectangle is at 5 meters from the bottom; two seconds later, it’s 10 meters below,” and so on.

    +

    While this provides for an amazingly accurate and robust physics engine (one that’s highly optimized and fast for C++ projects), it also necessitates lots of complicated code to translate back and forth between Box2D’s physics world and the world you want to draw—the pixel world of the graphics canvas. This creates a tremendous burden for the coder. I will, as best I can, continue to maintain a set of Box2D-compatible examples for this book (there are several JavaScript ports), but I believe the relative simplicity of working with a library like Matter.js that is native to JavaScript and uses pixels as the unit of measurement will make for a more intuitive and friendly bridge from my p5.js examples.

    +

    Another notable library is p5play, a project initiated by Paolo Pedercini and currently led by Quinton Ashley that was specifically designed for game development. It simplifies the creation of visual objects—known as sprites—and manages their interactions (namely, collisions and overlaps). As you may have guessed from the name, p5play is tailored to work seamlessly with p5.js. It uses Box2D under the hood for physics simulation.

    +

    Importing the Matter.js Library

    In a moment, I’ll turn to working with Matter.js, created by Liam Brummitt in 2014. But before you can use an external JavaScript library in a p5.js project, you need to import it into your sketch. As you’re already quite aware, I’m using the official p5.js web editor for developing and sharing this book’s code examples. The easiest way to add a library is to edit the index.html file that’s part of every new p5.js sketch created in the editor.

    diff --git a/content/08_fractals.html b/content/08_fractals.html index b9d17fb1..04d995b5 100644 --- a/content/08_fractals.html +++ b/content/08_fractals.html @@ -235,14 +235,15 @@

    Drawing the Cantor Set with Recur cantor(x + (2 * length / 3), y + 20, length / 3); }

    Since the cantor() function is now recursive, the same rule will be applied to the next line and to the next and to the next as cantor() calls itself again and again! But don’t go running this code quite yet. The sketch is missing that crucial element: an exit condition. It has to stop recursing at some point. Here, I’ll choose to stop if the line length is less than or equal to 1 pixel. In other words, keep going if length is greater than 1.

    -
    -

    Example 8.4: The Cantor Set

    -
    -
    -
    -
    -
    -
    function cantor(x, y, length) {
    +
    +
    +

    Example 8.4: The Cantor Set

    +
    +
    +
    +
    +
    +
    function cantor(x, y, length) {
       //{!1} Keep going as long as the length is greater than 1.
       if (length > 1) {
         line(x, y, x + length, y);
    @@ -250,6 +251,7 @@ 

    Example 8.4: The Cantor Set

    cantor(x + (2 * length) / 3, y + 20, length / 3); } }
    +

    Writing a function that recursively calls itself is a simple, elegant technique for generating a fractal pattern, but it doesn’t allow me to do much beyond drawing the pattern. For example, what if I want the lines in the Cantor set to exist as individual objects that could be moved independently? For that, I need to use a different programming approach, one that applies recursion in combination with an array that keeps track of all its individual parts. That’s exactly what I’ll do next!

    Exercise 8.1