noc-book-2/content/06_libraries.html
2023-08-16 18:13:08 +00:00

1767 lines
No EOL
146 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<section data-type="chapter">
<h1 id="chapter-6-physics-libraries">Chapter 6. Physics Libraries</h1>
<blockquote data-type="epigraph">
<p>“A library implies an act of faith / Which generations still in darkness hid / Sign in their night in witness of the dawn.”</p>
<p>— Victor Hugo</p>
</blockquote>
<p>Think about what youve accomplished so far in this book. Youve:</p>
<ol>
<li>Learned about concepts from the world of physics. (What is a vector? What is a force? What is a wave?)</li>
<li>Understood the math and algorithms behind those concepts.</li>
<li>Implemented those algorithms in p5.js with an object-oriented approach, culminating in building simulations of autonomous steering agents.</li>
</ol>
<p>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 arent 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.</p>
<p>Just try searching “open-source physics engine” and you could spend the rest of your day pouring over a host of rich and complex code bases. 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? Heres where the philosophy behind this book comes into play. While many of the libraries out there provide “out of the box” physics to experiment with (super awesome, sophisticate, and robust physics at that), there are several good reasons for learning the fundamentals from scratch before diving into such libraries.</p>
<p>First, without an understanding of vectors, forces, and trigonometry, its 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 wont necessarily simplify your code. There can be a great deal of overhead 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, its likely that you seek to create worlds and visualizations that stretch the limits of the imagination. A library may be great, but it only provides a limited set of features. Its important to know both when to live within those limitations in the pursuit of a creative coding project and when those limits will prove to be confining.</p>
<p>This chapter is dedicated to examining two open-source physics libraries for JavaScript: <a href="https://brm.io/matter-js/">Matter.js</a> and <a href="http://haptic-data.com/toxiclibsjs">toxiclibs.js</a>. I dont 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 the “Other Physics Libraries” box for some alternatives, and check the books website for ports of the chapters examples to other libraries). However, they both 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 Ive covered so far.</p>
<p>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 <em>any</em> 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.</p>
<h2 id="why-use-a-physics-library">Why Use a Physics Library?</h2>
<p>Ive made the case for writing your own physics simulations (as youve learned to do in the previous chapters), but whats the case for using a physics library? After all, anytime you add an external framework or library to a project, it introduces complexity and extra code. Is that additional overhead really worth it? If you just want to simulate a circle falling down due to 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. There are lots of scenarios like this that are simple enough for you to get by writing the code yourself.</p>
<p>But consider another scenario. What if you want to have 100 circles falling? And what if they actually arent circles at all, but rather irregularly shaped polygons? And what if you want these polygons to bounce off each other in a realistic manner when they collide?</p>
<p>You may have noticed that while Ive covered motion and forces in detail, Ive so far skipped over a rather important aspect of physics simulation: <strong>collisions</strong>. Lets pretend for a moment that you arent reading a chapter about physics libraries and that Ive decided right now to explain how to handle collisions in a particle system. Id have to cover two distinct algorithms that address two questions:</p>
<ol>
<li>How do I determine if two shapes are colliding (or intersecting)? This is known as <strong>collision detection</strong>.</li>
<li>How do I determine the shapes velocities after the collision? This is known as <strong>collision resolution</strong>.</li>
</ol>
<p>If youre working with simple geometric shapes, question #1 isnt too tough. In fact, perhaps youve encountered it before. With two circles, for instance, you know theyre intersecting if the distance between their centers is less than the sum of their radii (see Figure 6.1).</p>
<figure>
<img src="images/06_libraries/06_libraries_1.png" alt="Figure 6.1: Two circles with radii r_1 and r_2 are colliding if the distance between them is less than r_1 + r_2.">
<figcaption>Figure 6.1: Two circles with radii <span data-type="equation">r_1</span> and <span data-type="equation">r_2</span> are colliding if the distance between them is less than <span data-type="equation">r_1 + r_2</span>.</figcaption>
</figure>
<p>Thats easy enough, but how about calculating the circles velocities after the collision? This is where Im going to stop the discussion. Why, you ask? Its not that understanding the math behind collisions isnt important or valuable. (In fact, Im 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 cant expect to master every detail of physics simulation. And while you might enjoy learning about collision resolution for circles, its 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 . . .</p>
<p>Incorporating collisions into a p5.js sketch while still having time to spend with friends and family—thats 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. Theres no need to reinvent the proverbial wheel, at least for now.</p>
<p>In conclusion, if you find yourself describing an idea for a p5.js sketch and the word “collisions” comes up, then its likely time to learn to use a physics engine.</p>
<div data-type="note">
<h3 id="other-physics-libraries">Other Physics Libraries</h3>
<p>There are a multitude of other physics libraries worth exploring alongside this chapters 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 didnt 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. It 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. Its been used for countless projects, most notably highly successful games such as the award-winning <em>Crayon Physics</em> and the runaway hit <em>Angry Birds</em>.</p>
<p>One important feature of Box2D is that its 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. Its just that its “world” (a key term in Box2D) is a two-dimensional 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 worlds bottom.” Box2D will then tell you things like: “One second later, the rectangle is at 5 meters from the bottom; two seconds later, its 10 meters below,” and so on.</p>
<p>While this provides for an amazingly accurate and robust physics engine (one thats highly optimized and fast for C++ projects), it also necessitates lots of complicated code in order to translate back and forth between Box2Ds physics “world” and the world you want to draw —the pixel world of 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 thats 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.</p>
<p>Another notable library is <a href="https://p5play.org/">p5play</a>, 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.</p>
</div>
<h2 id="importing-the-matterjs-library">Importing the Matter.js Library</h2>
<p>In a moment, Ill turn to working with Matter.js, created by Liam [Last Name] in 2014. But before you can use an extrnal JavaScript library in a p5.js project, you need to import it into your sketch. As youre already quite aware, Im using the official p5.js web editor for developing and sharing this books code examples. The easiest way to add a library is to edit the <em>index.html</em> file thats part of every new p5.js sketch created in the editor.</p>
<p>To do that, first expand the file navigation bar on the lefthand side of the editor and select <em>index.html</em>, as shown in Figure 6.X.</p>
<figure>
<img src="images/06_libraries/06_libraries_2.png" alt="Figure 6.X: Accessing a sketchs index.html file">
<figcaption>Figure 6.X: Accessing a sketchs <em>index.html</em> file</figcaption>
</figure>
<p>The file includes a series of <code>&#x3C;script></code> tags inside the HTML tags <code>&#x3C;head></code> and <code>&#x3C;/head></code>. This is how JavaScript libraries are referenced in a p5.js sketch. Its no different than including <code>sketch.js</code> or <code>particle.js</code> in the pages <code>&#x3C;body></code>, only here, instead of keeping and editing a copy of the JavaScript code itself, the library is referenced with a URL of a <strong>content delivery network (CDN)</strong>. This is a type of server for hosting files. For JavaScript libraries that are used across hundreds of thousands of web pages that millions upon millions of users access, CDNs need to be pretty good at their job of serving up these libraries.</p>
<p>You should already see a <code>&#x3C;script></code> tag referencing the CDN for p5.js itself (it may be a later version by the time you are reading this):</p>
<pre class="codesplit" data-code-language="html">&#x3C;script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.js">&#x3C;/script></pre>
<p>To use Matter.js, just add another <code>&#x3C;script></code> tag referencing its CDN right below the one for p5:</p>
<pre class="codesplit" data-code-language="html">&#x3C;script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.js">&#x3C;/script>
&#x3C;script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.18.0/matter.min.js" integrity="sha512-5T245ZTH0m0RfONiFm2NF0zcYcmAuNzcGyPSQ18j8Bs5Pbfhp5HP1hosrR8XRt5M3kSRqzjNMYpm2+it/AUX/g==" crossorigin="anonymous" referrerpolicy="no-referrer">&#x3C;/script></pre>
<p>At the time of this writing, the most recent version of Matter.js was <code>0.18.0</code>, and thats what Ive referenced in the above snippet. As Matter.js updates and new versions are released, its often a good idea to upgrade, but by referencing a specific version that you know works with your sketch, you dont have to worry about new features of the library breaking your existing code.</p>
<h2 id="matterjs-overview">Matter.js Overview</h2>
<p>When you use Matter.js (or any physics engine) in p5.js, your code ends up looking a bit different. Heres a pseudocode generalization of all of the examples in Chapters 1 through 5:</p>
<p><code><strong>setup()</strong></code></p>
<ol>
<li>Create all the objects in the world.</li>
</ol>
<p><code><strong>draw()</strong></code></p>
<ol>
<li>Calculate all the forces in the world.</li>
<li>Apply all the forces to the objects (F = M * A).</li>
<li>Update the positions of all the objects based on their acceleration.</li>
<li>Draw all the objects.</li>
</ol>
<p>By contrast, heres the pseudocode for how a Matter.js example will appear:</p>
<p><code><strong>setup()</strong></code></p>
<ol>
<li>Create all the objects in the world.</li>
</ol>
<p><code><strong>draw()</strong></code></p>
<ol>
<li>Draw all the objects.</li>
</ol>
<p>This, of course, is the allure of a physics engine. Ive eliminated all of those painful steps of figuring out how the objects are moving according to velocity and acceleration. Matter.js is going to take care of this for me!</p>
<p>While there will be more details to reveal, the good news is that the simplicity of this pseudocode is an accurate reflect the overall process. In this sense, Matter is a bit like a magic box. In <code>setup()</code>, Im going to say to Matter: “Hello there. Here are all of the things I want in my world.” Then, in <code>draw()</code>, Im going to politely ask Matter: “Oh, hello again. If its not too much trouble, Id like to draw all of those things in my world. Could you please tell me where they are?”</p>
<p>The bad news: its not quite as simple as the pseudocode might lead you to believe. Actually making the stuff that goes into the Matter.js world involves several steps related to how different kinds of shapes are built and configured. Its also necessary to learn to speak the language of Matter.js in terms of how the various forces and other parameters of the world are configured. Here are the core concepts:</p>
<ol>
<li><strong>Engine.</strong> The entity that manages the physics simulation itself. The engine holds on to the “world” of the simulation as well as various properties about how the world is updated over time.</li>
<li><strong>Bodies.</strong> Serve as the primary elements in the world, corresponding to the physical objects being simulated. A body has a position, and it has a velocity. Sound familiar? Its basically another version of the class Ive been building all throughout Chapters 1 through 5. It also has geometry to define its shape. Its important to note that “body” is a generic term that physics engines use to describe a “thing” in the world (similarly to the term “particle”); it isnt related to an anthropomorphic body.</li>
<li><strong>Composite.</strong> A container that allows for the creation of complex entities (made up of multiple bodies). The world itself is an example a composite, and every body created has be added to the world.</li>
<li><strong>Constraints.</strong> Act as connections between bodies.</li>
</ol>
<p>In the coming sections, Ill walk through each of these elements in detail, building several examples along the way. But first, theres one other important element to briefly discuss.</p>
<ol>
<li><strong>Vector.</strong> Describes a vector in a Matter.js world.</li>
</ol>
<p>This brings us to an important crossroads. Any physics library is going to involve the concept of a vector, and depending on how you spin it, thats either a good or a bad thing. The good part is that youve just spent several chapters familiarizing yourself with what it means to describe motion and forces with vectors, so theres nothing conceptually new for you to learn. The bad part—the part that makes a single tear fall from my eye—is that once you cross this threshold into the brave new world of physics libraries, you dont get to use <code>p5.Vector</code> anymore.</p>
<p>Its been great that p5.js has a built-in vector representation, but anytime you use a physics library, youll likely discover that it includes its own separate vector implementation, designed to be especially compatible with the rest of the librarys code. This makes sense. After all, why should Matter.js be expected to know about <code>p5.Vector</code>objects?</p>
<p>The upshot of all this is that while you wont have to learn any new concepts, you do have to get used to some new naming conventions and syntax. To illustrate, Ill show you some now-familiar <code>p5.Vector</code> operations alongside the equivalent <code>Matter.Vector</code> code. First, how do you create a vector?</p>
<table>
<thead>
<tr>
<th>p5.js</th>
<th>Matter.js</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<pre class="codesplit" data-code-language="javascript">let v = createVector(1, -1);</pre>
</td>
<td>
<pre class="codesplit" data-code-language="javascript">let v = Matter.Vector.create(1, -1);</pre>
</td>
</tr>
</tbody>
</table>
<p>What about adding two vectors together?</p>
<table>
<thead>
<tr>
<th>p5.js</th>
<th>Matter.js</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<pre class="codesplit" data-code-language="javascript">let a = createVector(1, -1);
let b = createVector(3, 4);
a.add(b);</pre>
</td>
<td>
<pre class="codesplit" data-code-language="javascript">let a = Matter.Vector.create(1, -1);
let b = Matter.Vector.create(3, 4);
Matter.Vector.add(a, b, a);</pre>
</td>
</tr>
</tbody>
</table>
<p>That overwrites vector <code>a</code> with the result. Heres how to put the result in a separate vector instead.</p>
<table>
<thead>
<tr>
<th>p5.js</th>
<th>Matter.js</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<pre class="codesplit" data-code-language="javascript">let a = createVector(1, -1);
let b = createVector(3, 4);
let c = p5.Vector.add(a, b);</pre>
</td>
<td>
<pre class="codesplit" data-code-language="javascript">let a = Matter.Vector.create(1, -1);
let b = Matter.Vector.create(3, 4);
let c = Matter.Vector.add(a, b);</pre>
</td>
</tr>
</tbody>
</table>
<p>How about if you want to scale the vector (multiply by a scalar value)?</p>
<table>
<thead>
<tr>
<th>p5.js</th>
<th>Matter.js</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<pre class="codesplit" data-code-language="javascript">let v = createVector(1, -1);
v.mult(4);</pre>
</td>
<td>
<pre class="codesplit" data-code-language="javascript">let v = Matter.Vector.create(1, -1);</pre><code>v = Matter.Vector.mult(v, 4);</code>
</td>
</tr>
</tbody>
</table>
<p>Magnitude and normalize?</p>
<table>
<thead>
<tr>
<th>p5.js</th>
<th>Matter.js</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<pre class="codesplit" data-code-language="javascript">let v = createVector(3, 4);
let m = v.mag();
v.normalize();</pre>
</td>
<td>
<pre class="codesplit" data-code-language="javascript">let v = Matter.Vector.create(3, 4);
let m = Matter.Vector.magnitude(v);
v = Matter.Vector.normalise(v);</pre>
</td>
</tr>
</tbody>
</table>
<p>As you can see, the concepts are the same, but the specifics of the code are different. First, every method name is now preceded by <code>Matter.Vector</code>, which defines the <strong>namespace</strong> of the source code. This is common for JavaScript libraries; p5.js is the unusual one for not consistently using namespaces. For example, to draw a circle in p5.js, you call <code>circle()</code> rather than <code>p5.circle()</code>. The <code>circle()</code> function lives in the “global” namespace. This, in my view, is one of the features that makes p5.js special in terms of ease of use and beginner friendliness. However, it also means that for any code you write with p5, you cant use <code>circle</code> as a variable name. Namespacing a library protects against these kinds of errors and naming conflicts, and its why youll see everything in Matter.js called with the <code>Matter</code> prefix.</p>
<p>In addition, unlike p5s static and non-static versions of vector methods like <code>add()</code> and <code>mult()</code>, all vector methods in Matter are static. If you want to change a <code>Matter.Vector</code> while operating on it, you can add it as an optional argument: <code>Matter.Vector.add(a, b, a)</code>: adds <code>a</code> and <code>b</code> and places the result in <code>a</code> (the third argument). You can also set an existing variable to the newly created vector object resulting from a calculation, as in <code>v = Matter.Vector.mult(v, 2)</code>. However, this version still creates a new vector in memory rather than updating the old one.</p>
<p>Ill cover more of the basics of what you need to know for working with <code>Matter.Vector</code> in this chapter, but for more, <a href="https://brm.io/matter-js/docs/classes/Vector.html">full documentation</a> can be found on the Matter.js website.</p>
<h3 id="engine">Engine</h3>
<p>Many physics libraries include a “world” object to manage everything. The world is typically in charge of the coordinate space, keeping a list of all the bodies in the simulation, controlling time, and more. In Matter.js, the “world” is created inside of an <code>Engine</code> object, the main controller of your physics world and simulation.</p>
<pre class="codesplit" data-code-language="javascript">// An "alias" for the Matter.js Engine class
let Engine = Matter.Engine;
// A reference to the Matter physics engine
let engine;
function setup() {
createCanvas(640, 360);
// Create the Matter engine
engine = Engine.create();
}</pre>
<p>Notice how the very first line of code creates an <code>Engine</code> variable and sets it equal to <code>Matter.Engine</code>. Here, Im deciding to point the single keyword <code>Engine</code> to the <code>Engine</code> class namespaced inside Matter.js in order to make my code less verbose. This works because I know I wont be using the word <code>Engine</code> for any other variables, nor does it conflict with something in p5.js. Ill be doing this with <code>Vector</code>, <code>Bodies</code>, <code>Composite</code>, and more as I continue to build the examples. (But while the linked source code will always include all the aliases, I wont always show them in the book text itself.)</p>
<div data-type="note">
<h3 id="object-destructuring">Object Destructuring</h3>
<p><strong>Object destructuring</strong> in JavaScript is a technique for extracting properties from an object and assigning them to variables. In the case of Matter.js, the <code>Matter</code> object contains the <code>Engine</code> property. Normally, an alias for this property can be set with <code>let Engine = Matter.Engine</code>, but with destructuring, the alias can be created more concisely:</p>
<pre class="codesplit" data-code-language="javascript">let { Engine } = Matter </pre>
<p>This syntax really shines when you need to create aliases to multiple properties of the same object:</p>
<pre class="codesplit" data-code-language="javascript">// Using Object Destructuring to extract aliases for Engine and Vector
let { Engine, Vector } = Matter;</pre>
<p>This sets up <code>Engine</code> as an alias for <code>Matter.Engine</code> and <code>Vector</code> as an alias for <code>Matter.Vector</code>, all in one statement. Ill use this technique throughout the chapters examples.</p>
</div>
<p>When you call <code>create()</code> on <code>Engine</code>, Matter.js returns a new physics engine and world with a default gravity—a vector <span data-type="equation">(0,1)</span> pointing down. You can change this default by accessing the <code>gravity</code> variable itself:</p>
<pre class="codesplit" data-code-language="javascript"> // Changing the engine's gravity to point horizontally
engine.gravity.x = 1;
engine.gravity.y = 0;</pre>
<p>Of course, gravity doesnt have to be fixed for the duration of the simulation; you can adjust the gravity vector while your program is running. You can also turn gravity off altogether by setting it to a <span data-type="equation">(0,0)</span> vector.</p>
<p>Once the world is initialized, its time to actually put stuff in it—bodies!</p>
<h3 id="bodies">Bodies</h3>
<p>The <strong>body</strong> is the primary element in the Matter.js world. Its the equivalent to the <code>Vehicle</code> née <code>Particle</code> née <code>Mover</code> class I built in previous chapters—the thing that moves around the space and experiences forces. A body can also be static (meaning fixed and not moving).</p>
<p>Matter.js bodies are created using “factory” methods found in <code>Matter.Bodies</code>, with different methods available for creating different kinds of bodies. A <strong>factory method</strong> is a function that creates an object. While youre probably more familiar with calling a constructor to create an object, for example with <code>new Particle()</code>, youve seen factory methods before: <code>createVector()</code> is a factory method for creating a <code>p5.Vector</code> object. Whether an object is created from a constructor or a factory method, is a matter of style and design choice by a library creator.</p>
<p>All of the factory methods for creating bodies can be found in the <code>Matter.Bodies</code> <a href="https://brm.io/matter-js/docs/classes/Bodies.html">documentation page</a>. Ill start with the <code>rectangle()</code> method.</p>
<pre class="codesplit" data-code-language="javascript">// Create a Matter.js Body with a rectangular shape
let box = Bodies.rectangle(x, y, w, h);</pre>
<p>What luck! The <code>rectangle()</code>method signature is exactly the same as p5.jss <code>rect()</code> function. In this case, however, the method isnt <em>drawing</em> a rectangle but rather building the geometry for a <code>Body</code> object to store. (Note that calling <code>Bodies.rectangle()</code> only works if you first establish <code>Bodies</code> as an alias to <code>Matter.Bodies</code>.)</p>
<p>A body has now been created with a position and a size, and a reference to it is stored in the variable <code>box</code>. Bodies have many more properties that affect its motion, however. For example, theres density, which ultimately determines that bodys mass. Friction and restitution (“bounciness”) affect how the body interacts when it comes into contact with other bodies. For most cases, the defaults are sufficient, but Matter.js does allow you to specify these properties by passing through an additional argument to the factory method in the form of a JavaScript object literal.</p>
<pre class="codesplit" data-code-language="javascript">//{!5} Specify additional properties of this Matter.js Body
let options = {
friction: 0.5,
restitution: 0.8,
density: 0.002
}
let box = Matter.Bodies.rectangle(x, y, w, h, options);</pre>
<p>While the <code>options</code> variable is useful for configuring the body, other initial conditions, such as linear or angular velocity, can be set via static methods of the <code>Matter.Body</code> class.</p>
<pre class="codesplit" data-code-language="javascript">// Setting arbitrary initial linear and angular velocity
const v = Vector.create(2, 0);
Body.setVelocity(box, v);
Body.setAngularVelocity(box, 0.1);</pre>
<p>Creating a body and storing it in a variable isnt enough. Any body must be explicitly added to the “world” in order for it to be simulated with physics. The physics world is a <code>Composite</code> object called <code>world</code> stored inside on the <code>engine</code> itself. The <code>box</code> can be added to that world with the static <code>add()</code> method</p>
<pre class="codesplit" data-code-language="javascript">// Add the box object to the engine's world
Composite.add(engine.world, box);</pre>
<p>This extra step is easy to forget—its a mistake Ive made on countless occasions. If youre ever wondering why one of your objects doesnt appear or move along with the worlds physics, always check if youve actually added it to the world!</p>
<div data-type="exercise">
<h3 id="exercise-61">Exercise 6.1</h3>
<p>Knowing what you know about Matter.js so far, fill in the blank in the code below that demonstrates how to make a circular body.</p>
<pre class="codesplit" data-code-language="javascript">let options = {
friction: 0.5,
restitution: 0.8,
}
let ball = <span class="blank">Bodies</span>.<span class="blank">circle</span>(<span class="blank">x</span>, <span class="blank">y</span>, <span class="blank">radius</span>, options);</pre>
</div>
<h3 id="render">Render</h3>
<p>Once a body is added the world, Matter.js will always know its there, check it for collisions, and update its position appropriately according to any forces in the environment. Itll do all that for you without you having to lift a finger! But how do you actually draw the body?</p>
<p>In the next section, Ill show you how to query Matter.js for the position of the various bodies in order to render the world with p5.js. How that works is fundamental to being able to control the look of your own animations. This is your time to shine: you can be the designer of your world, using your creativity and p5.js skills to visualize the bodies, while politely asking Matter.js to compute all the physics in the background.</p>
<p>That said, Matter.js does include a fairly simple and straightforward <code>Render</code> class, which is incredibly useful for quickly seeing and debugging the world youve designed. It provides ways to customize the “debug drawing” style, but I find the defaults perfectly adequate for quickly double-checking that Ive configured a world correctly.</p>
<p>The first step is to call <code>Matter.Render.create()</code> (or <code>Render.create()</code> assuming an alias). This method expects an object with the desired settings for the renderer,which Ill call <code>params</code>.</p>
<pre class="codesplit" data-code-language="javascript">// Store the canvas in a variable
let canvas = createCanvas(640, 360);
// Configure the renderer
let params = {
canvas: canvas.elt,
engine: engine,
options = { width: width, height: height }
}
// Create the renderer
let render = Render.create(params);</pre>
<p>Notice how Im storing a reference to the p5.js canvas in the <code>canvas</code> variable. This is necessary because I need to tell the renderer to draw into a specific canvas. Matter.js doesnt know about p5.js, so the canvas its assigned is a native HTML5 canvas, stored inside the <code>elt</code> property of a p5.js canvas object. The engine is the <code>engine</code> I previously created. The Matter.js default canvas dimensions are 800 by 600, so if I prefer a different size, I need to configure an <code>options</code> property with <code>width</code> and <code>height</code>.</p>
<p>Once I have a <code>render</code> object, I need to tell Matter.js to run it.</p>
<pre class="codesplit" data-code-language="javascript">// Run the renderer!
Render.run(render);</pre>
<p>Theres one more critical order of business: physics engines must be told to “step” forward in time. Since Im using the built-in renderer, I can also use the built-in “runner,” which runs the engine at a default framerate of 60 frames per second. The runner is also customizable, but the details arent terribly important since the goal here is to move toward using p5.jss <code>draw()</code> loop instead (coming in the next section).</p>
<pre class="codesplit" data-code-language="javascript">// Run the engine!
Runner.run(engine);</pre>
<p>Heres all of the Matter.js code all together, with an added <code>ground</code> object—another rectangular body. Note the use of the <code>{ isStatic: true }</code> option in the creation of ground body to ensure that it remains in a fixed position. Ill cover more details about static bodies later in the chapter.</p>
<div data-type="example">
<h3 id="example-61-matterjs-default-render-and-runner">Example 6.1: Matter.js Default Render and Runner</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/GXRa48IQO" data-example-path="examples/06_libraries/6_1_default_matter_js"><img src="examples/06_libraries/6_1_default_matter_js/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">// {!1} Note the use of aliases for all of the Matter.js classes needed for this sketch.
const { Engine, Bodies, Composite, Body, Vector } = Matter;
function setup() {
// Store a reference to the canvas
let canvas = createCanvas(640, 360);
// Create the physics engine
let engine = Engine.create();
// Create a renderer and assign to the p5.js canvas
const render = Matter.Render.create({
canvas: canvas.elt,
engine,
options: { width, height },
});
Matter.Render.run(render);
// Create a box with custom friction and restitution
let options = {
friction: 0.01,
restitution: 0.75,
};
let box = Bodies.rectangle(100, 100, 50, 50, options);
// Set initial velocity of box
Body.setVelocity(box, Vector.create(5, 0));
Body.setAngularVelocity(box, 0.1);
// Add box to the world
Composite.add(engine.world, box);
// Create a static body for the ground
let ground = Bodies.rectangle(width / 2, height - 5, width, 10, {
isStatic: true,
});
Composite.add(engine.world, ground);
// Create runner
let runner = Matter.Runner.create();
// Run the engine
Matter.Runner.run(runner, engine);
}</pre>
<p>Theres no <code>draw()</code> function here, and all of the variables are local to <code>setup()</code>. In fact, Im not making use of any of the capabilities of p5.js (beyond injecting a canvas onto the page). This is exactly what I want to tackle next!</p>
<h2 id="matterjs-with-p5js">Matter.js with p5.js</h2>
<p>Matter.js keeps a list of all bodies that exist in the world, and as youve just seen, it can handle drawing and animating them with the <code>Render</code> and <code>Runner</code> objects. (That list, incidentally, is stored in <code>engine.world.bodies</code>.) What Id like to show you now, however, is a technique for keeping your own list(s) of Matter.js bodies, so you can draw them with p5. Yes, this approach may add redundancy and sacrifice a small amount of efficiency, but it more than makes up for that with ease of use and customization. With this methodology, youll be able to code like youre accustomed to in p5.js, keeping track of which bodies are which and drawing them appropriately. Consider the file structure of the sketch shown in Figure 6.x.</p>
<figure>
<img src="images/06_libraries/06_libraries_3.png" alt="Figure 6.x: The file structure of a typical p5.js sketch">
<figcaption>Figure 6.x: The file structure of a typical p5.js sketch</figcaption>
</figure>
<p>Structurally, this looks like just another p5.js sketch. Theres a main <em>sketch.js</em> file, as well as <em>box.js</em>. This sort of extra file is where Id typically declare a class needed for the sketch—in this case, a <code>Box</code> class describing a rectangular body in the world.</p>
<pre class="codesplit" data-code-language="javascript">class Box {
constructor(x, y) {
//{!3} A box has an x,y position and a width.
this.x = x;
this.y = y;
this.w = 16;
}
show() {
//{!5} The box is drawn as a square().
rectMode(CENTER);
fill(127);
stroke(0);
strokeWeight(2);
square(this.x, this.y, this.w);
}
}</pre>
<p>Now Ill write a <em>sketch.js</em> file that creates a new <code>Box</code> whenever the mouse is pressed and stores all the <code>Box</code> objects in an array. (This is the same approach I took in the particle system examples from Chapter 4.)</p>
<div data-type="example">
<h3 id="example-62-a-comfortable-and-cozy-p5js-sketch-that-needs-a-little-matterjs">Example 6.2: A Comfortable and Cozy p5.js Sketch That Needs a Little Matter.js</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/D26YvXr_S" data-example-path="examples/06_libraries/6_2_boxes_exercise"><img src="examples/06_libraries/6_2_boxes_exercise/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">//{!1} An array to store all Box objects
let boxes = [];
function setup() {
createCanvas(640, 360);
}
function draw() {
background(255);
//{!3} When the mouse is pressed, add a new Box object.
if (mouseIsPressed) {
let box = new Box(mouseX, mouseY);
boxes.push(box);
}
//{!3} Display all the Box objects.
for (let i = 0; i &#x3C; boxes.length; i++) {
boxes[i].show();
}
}</pre>
<p>Right now this sketch draws fixed boxes to the screen. Heres the challenge: how can I instead draw boxes that experience physics (calculated with Matter.js) as soon as they appear, while changing the code as little as possible?</p>
<p>Ill need three steps to accomplish this goal.</p>
<h3 id="step-1-add-matterjs-to-the-p5js-sketch">Step 1: Add Matter.js to the p5.js Sketch</h3>
<p>As it stands, the sketch makes no reference to Matter.js. That clearly needs to change. Fortunately, this part isnt too tough: Ive already demonstrated all the elements needed to build a Matter.js world. (And dont forget, in order for this to work, make sure the library is imported in <em>index.html.</em>)</p>
<p>First, I need to add aliases for the necessary Matter classes and create an <code>Engine</code> object in <code>setup()</code>:</p>
<pre class="codesplit" data-code-language="javascript">//{!3} Aliases for Engine, Bodies, and Composite
let { Engine, Bodies, Composite } = Matter;
//{!1} The engine is now a global variables!
let engine;
function setup() {
//{!1} Create the engine.
engine = Engine.create();
}</pre>
<p>Then, in <code>draw()</code>, I need to make sure to call one critical Matter.js method: <code>Engine.update()</code>.</p>
<pre class="codesplit" data-code-language="javascript">function draw() {
//{!1} Step the engine forward in time!
Engine.update(engine);
}</pre>
<p>The <code>Engine.update()</code> method advances the physics world one step forward in time. Calling it inside the p5.js <code>draw()</code> loop ensures that the physics will update at every frame of the animation. This mechanism takes teh place of the built-in Matter.js <code>Runner</code> object I used in Example 6.1. The <code>draw()</code> loop is the runner now!</p>
<p>Internally, when <code>Engine.update()</code> is called, Matter.js sweeps through the world, looks at all of the bodies in it, and figures out what to do with them. Just calling <code>Engine.update()</code> on its own moves the world forward with default settings. However, as with <code>Render</code>, these settings are customizable (and documented in the <a href="https://brm.io/matter-js/docs/classes/Engine.html#method_update">Matter.js reference</a>).</p>
<h3 id="step-2-link-every-box-object-with-a-matterjs-body">Step 2: Link Every Box Object with a Matter.js Body</h3>
<p>Ive set up my Matter.js world; now I need to link each <code>Box</code> object in my p5.js sketch with a body in that world. The original <code>Box</code> class includes variables for position and width. What I now want to say is: “I hereby relinquish command of this objects position to Matter.js. I no longer need to keep track of anything related to position, velocity, or acceleration. Instead, I only need to keep track of the existence of a Matter.js body and have faith that the physics engine will do the rest.”</p>
<pre class="codesplit" data-code-language="javascript">class Box {
constructor(x, y) {
this.w = 16;
//{!1} Instead of any of the usual variables, store a reference to a body.
this.body = Bodies.rectangle(x, y, this.w, this.w);
//{!1} Don't forget to add it to the world!
Composite.add(engine.world, this.body);
}</pre>
<p>I dont need <code>this.x</code> and <code>this.y</code> position variables anymore. The <code>Box</code> constructor takes in the starting <span data-type="equation">(x, y)</span> coordinates, passes them along to <code>Bodies.rectangle()</code> to create a new Matter.js body, and then forgets about them. As youll see, the body itself will keep track of its position behind the scenes. The body could technically keep track of its dimensions as well, but since Matter.js stores them as a list of vertices, its a bit more convenient to hold onto the width of the square in the <code>this.w</code> variable for when it comes time to draw the box.</p>
<h3 id="step-3-draw-the-box-body">Step 3: Draw the Box Body</h3>
<p>Almost there. Before I introduced Matter.js into the sketch, it was easy to draw the <code>Box</code>. The objects position was stored in variables <code>this.x</code> and <code>this.y</code>.</p>
<pre class="codesplit" data-code-language="javascript"> // Drawing the object using square()
show() {
rectMode(CENTER);
fill(127);
stroke(0);
strokeWeight(2);
square(this.x, this.y, this.w);
}</pre>
<p>Now that Matter.js manages the objects position, I can no longer use my own <code>x</code> and <code>y</code>variables to draw the shape. But fear not! The <code>Box</code> object has a reference to the Matter.js body associated with it, and that body knows its own position. All I need to do is politely ask the body, “Pardon me, where are you located?”</p>
<pre class="codesplit" data-code-language="javascript">let position = this.body.position;</pre>
<p>Just knowing the position of a body isnt enough, however. The body is a square, so I also need to know its angle of rotation.</p>
<pre class="codesplit" data-code-language="javascript">let angle = this.body.angle;</pre>
<p>Once I have the position and angle, I can render the object using the native p5.js <code>translate()</code>, <code>rotate()</code>, and <code>square()</code> functions.</p>
<pre class="codesplit" data-code-language="javascript"> show() {
//{!2} I need the Bodys position and angle.
let position = this.body.position;
let angle = this.body.angle;
rectMode(CENTER);
fill(127);
stroke(0);
strokeWeight(2);
push();
//{!2} Use the position and angle to translate and rotate the square.
translate(position.x, position.y);
rotate(angle);
square(0, 0, this.w);
pop();
}</pre>
<p>Its important to note here that if you delete a <code>Box</code> objects from the <code>boxes</code> array—perhaps when it moves outside the boundaries of the canvas or reaches the end of its lifespan, as demonstrated in Chapter 4—you must also explicitly remove the body associated with that <code>Box</code> object from the Matter.js world. This can be done with a <code>removeBody()</code> method on the <code>Box</code> class.</p>
<pre class="codesplit" data-code-language="javascript"> // This function removes a body from the Matter.js world.
removeBody() {
Composite.remove(engine.world, this.body);
}</pre>
<p>In <code>draw()</code>, you would then iterate over the array in reverse, just as in the particle system examples, an call both <code>removeBody()</code> and <code>splice()</code> to delete the object from the Matter.js world and your array of boxes.</p>
<div data-type="exercise">
<h3 id="exercise-62">Exercise 6.2</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/oIZSHFXXk" data-example-path="examples/06_libraries/6_2_boxes_solved"><img src="examples/06_libraries/6_2_boxes_solved/screenshot.png"></div>
<figcaption>Drag the mouse to add boxes.</figcaption>
</figure>
<p>Start with the code for Example 6.2 and, using the methodology outlined in this chapter, add the code to implement Matter.js physics. Delete bodies that have left the canvas. The result should appear as above. Feel free to be creative in how you draw the boxes!</p>
</div>
<h2 id="static-matterjs-bodies">Static Matter.js Bodies</h2>
<p>In the example I just created, the <code>Box</code> objects appear at the mouse position and fall downwards due to the default gravity force. What if I want to add immovable boundaries to the world that will block the path of the falling <code>Box</code> objects? Matter.js makes this easy with the <code>isStatic</code> property.</p>
<pre class="codesplit" data-code-language="javascript">// Creating a fixed (static) boundary body
let options = { isStatic: true };
let boundary = Bodies.rectangle(x, y, w, h, options);</pre>
<p>Im still creating a body with the <code>Bodies.rectangle()</code> factory method, but setting the <code>isStatic</code> property ensures that the body will never move. Ill incorporate this feature into the solution to Exercise 6.2 by creating a separate <code>Boundary</code> class that links a p5.js rectangle to a static Matter.js body. For variety, Ill also randomize the dimensions of each falling box. (See the online code for the changes to the <code>Box</code> class.)</p>
<div data-type="example">
<h3 id="example-63-falling-boxes-hitting-boundaries">Example 6.3: Falling boxes hitting boundaries</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/WSoUy03ph" data-example-path="examples/06_libraries/6_3_boxes_and_boundaries"><img src="examples/06_libraries/6_3_boxes_and_boundaries/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">class Boundary {
constructor(x, y, w, h) {
//{!4} A boundary is a simple rectangle with x, y, width, and height.
this.x = x;
this.y = y;
this.w = w;
this.h = h;
//{!1} Lock it in place by setting isStatic to true!
let options = { isStatic: true };
this.body = Bodies.rectangle(this.x, this.y, this.w, this.h, options);
Composite.add(engine.world, this.body);
}
//{!6} Since it can never move, show() can draw it
// the old-fashioned way, using the original
// variables. No need to query Matter.js.
show() {
rectMode(CENTER);
fill(127);
stroke(0);
strokeWeight(2);
rect(this.x, this.y, this.w, this.h);
}
}</pre>
<p>Static bodies dont incorporate “material” properties like <code>restitution</code> or <code>friction</code>. Make sure you set those in the dynamic bodies in your world.</p>
<h2 id="polygons-and-groups-of-shapes">Polygons and Groups of Shapes</h2>
<p>Now that Ive demonstrated how easy it is to use a primitive shape like a rectangle or circle with Matter.js, lets imagine that you want to have a more interesting body, such as the abstract character in Figure 6.2.</p>
<figure>
<img src="images/06_libraries/06_libraries_4.png" alt="Figure 6.2: A “compound” body made up of multiple shapes">
<figcaption>Figure 6.2: A “compound” body made up of multiple shapes</figcaption>
</figure>
<p>There are two strategies for making such complex forms. Beyond the four sides of a rectangle, theres a generic <code>Bodies.polygon()</code> method for creating any regular polygon (pentagon, hexagon, and so on). Additionally, theres <code>Bodies.trapezoid()</code> for making a quadrilateral with at least one pair of parallel sides.</p>
<pre class="codesplit" data-code-language="javascript">// A regular hexagon (6 sided polygon)
let hexagon = Bodies.polygon(x, y, 6, radius);
// A trapezoid
let trapezoid = Bodies.trapezoid(x, y, width, height, slope);</pre>
<p>A more general-purpose option is <code>Bodies.fromVertices()</code>. It builds a shape from an array of vectors, treating them as a series of connected vertices. Ill encapsulate this logic in a <code>CustomShape</code> class.</p>
<div data-type="example">
<h3 id="example-64-polygon-shapes">Example 6.4: Polygon Shapes</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/o3-Qpqu2i" data-example-path="examples/06_libraries/6_4_polygon_shapes"><img src="examples/06_libraries/6_4_polygon_shapes/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">
class CustomShape {
constructor(x, y) {
//{!6} An array of 5 vectors
let vertices = [];
vertices[0] = Vector.create(-10, -10);
vertices[1] = Vector.create(20, -15);
vertices[2] = Vector.create(15, 0);
vertices[3] = Vector.create(0, 10);
vertices[4] = Vector.create(-20, 15);
//{!2} Making a body from shaped by the vertices
let options = { restitution: 1 };
this.body = Bodies.fromVertices(x, y, vertices, options);
Body.setVelocity(this.body, Vector.create(random(-5, 5), 0));
Body.setAngularVelocity(this.body, 0.1);
Composite.add(engine.world, this.body);
}</pre>
<p>When creating a custom polygon in Matter.js, you must remember two important details. First, the vertices must be specified in clockwise order. For instance, Figure 6.3 shows the five vertices used to create the bodies in Example 6.4. Notice how the example added them to the <code>vertices</code> array in clockwise order from the top-left.</p>
<figure>
<img src="images/06_libraries/06_libraries_5.png" alt="Figure 6.3: Vertices on a custom polygon oriented in clockwise order">
<figcaption>Figure 6.3: Vertices on a custom polygon oriented in clockwise order</figcaption>
</figure>
<p>Second, each shape must be convex, not concave. As shown in Figure 6.4, a <strong><em>concave</em></strong> shape is one where the surface curves inward, whereas <strong><em>convex</em></strong> is the opposite. Every internal angle in a convex shape must be 180 degrees or less. Matter.js can in fact work with concave shapes, but you need to build them out of multiple convex shapes. (More about that in a moment.)</p>
<figure>
<img src="images/06_libraries/06_libraries_6.png" alt="Figure 6.4: A concave shape can be drawn with multiple convex shapes. ">
<figcaption>Figure 6.4: A concave shape can be drawn with multiple convex shapes. </figcaption>
</figure>
<p>Since the shape is built out of custom vertices, you can use p5s <code>beginShape()</code>, <code>endShape()</code>, and <code>vertex()</code> functions when it comes time to actually draw the body. The <code>CustomShape</code> class <em>could</em> include an array to store the vertices pixel positions, relative to <span data-type="equation">(0, 0)</span>, for drawing purposes. However, its best to query Matter.js for the positions instead. This way theres no need to use <code>translate()</code> or <code>rotate()</code>, since the Matter.js body stores its vertices as absolute “world” positions.</p>
<pre class="codesplit" data-code-language="javascript"> show() {
fill(127);
stroke(0);
strokeWeight(2);
// Start the shape
beginShape();
//{!3} Loop through the body vertices
for (let v of this.body.vertices) {
vertex(v.x, v.y);
}
// End the shape, closing it
endShape(CLOSE);
}</pre>
<p>The Matter.js body stores the array of its vertex positions inside a <code>vertices</code> property. Notice how I can then use a <code>for...of</code> loop to cycle through the vertices in between <code>beginShape()</code> and <code>endShape()</code>.</p>
<div data-type="exercise">
<h3 id="exercise-63">Exercise 6.3</h3>
<p>Using <code>Bodies.fromVertices()</code>, create your own polygon design (remember, it must be convex). Some possibilities are shown below.</p>
<figure>
<img src="images/06_libraries/06_libraries_7.png" alt=" ">
<figcaption> </figcaption>
</figure>
</div>
<p>A custom shape built from an array of vertices will get you pretty far. However, the convex shape requirement does limit the range of possibilities. The good news is that you can eliminate this restriction by creating a <strong><em>compound body</em></strong> made up of multiple shapes! How about creating a delicious lollipop with a thin rectangle and a circle on top?</p>
<p>Ill start by creating two individual bodies, one rectangle and one circle. Then I can join them by putting them in a <code>parts</code> array and passing the array to <code>Body.create()</code>.</p>
<pre class="codesplit" data-code-language="javascript">// Making the bodies
let part1 = Bodies.rectangle(x, y, w, h);
let part2 = Bodies.circle(x, y, r);
// Joining the two bodies together in an array
let body = Body.create({ parts: [part1, part2] });
// Adding the compound body to the world
Composite.add(engine.world, body);</pre>
<p>While this does create a compound body by combining two shapes, the code isnt quite right. If you run it, youll see that both shapes are centered around the same <span data-type="equation">(x, y)</span> position, as in Figure 6.5.</p>
<figure>
<img src="images/06_libraries/06_libraries_8.png" alt="Figure 6.5: A rectangle and a circle with the same (x, y) reference point.">
<figcaption>Figure 6.5: A rectangle and a circle with the same <span data-type="equation">(x, y)</span> reference point.</figcaption>
</figure>
<p>Instead, I need to offset the center of the circle horizontally from the center of the rectangle, as in Figure 6.6.</p>
<figure>
<img src="images/06_libraries/06_libraries_9.png" alt="Figure 6.6: A circle placed relative to a rectangle with a horizontal offset">
<figcaption>Figure 6.6: A circle placed relative to a rectangle with a horizontal offset</figcaption>
</figure>
<p>Ill use half the width of the rectangle as the offset, so the circle is centered around the edge of the rectangle.</p>
<pre class="codesplit" data-code-language="javascript">
let part1 = Bodies.rectangle(x, y, w, h);
//{!2} Adding an offset from the x position of the lollipop's "stick"
let offset = w / 2;
let part2 = Bodies.circle(x + offset, y, r);</pre>
<p>Because there are two “parts” to the lollipops body, drawing it is a bit trickier. There are multiple approaches I could take. For example, I could use the bodys <code>vertices</code> array and draw the lollipop as a custom shape, much like in Example 6.4. (Every body stores an array of vertices, even if it wasnt created with the <code>fromVertices()</code> method.) Since each part of the lollipop is a primitive shape, however, Id prefer to separately translate to each parts position and rotate by the collective bodys angle.</p>
<div data-type="example">
<h3 id="example-65-multiple-shapes-on-one-body">Example 6.5: Multiple Shapes on One Body</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/xxYF4I5bi" data-example-path="examples/06_libraries/6_5_compound_bodies"><img src="examples/06_libraries/6_5_compound_bodies/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript"> show() {
// The angle comes from the compound body
let angle = this.body.angle;
//{!2} Get the position for each part
let position1 = this.part1.position;
let position2 = this.part2.position;
fill(200);
stroke(0);
strokeWeight(1);
// Translate and rotate the rectangle (part1)
push();
translate(position1.x, position1.y);
rotate(angle);
rectMode(CENTER);
rect(0, 0, this.w, this.h);
pop();
// Translate and rotate the circle (part2)
push();
translate(position2.x, position2.y);
rotate(angle);
circle(0, 0, this.r * 2);
pop();
}</pre>
<p>Before moving on, I want to stress the following: what you draw in your canvas window doesnt magically experience perfect physics just by the mere act of creating Matter.js bodies. The chapters examples have worked because Ive been carefully matching how each p5.js shape is drawn with how the geometry of each Matter.js body is defined. If you accidentally draw a shape differently, you wont get an error—not from p5.js or from Matter.js. However, your sketch will look odd, and the physics wont work correctly because the world youre seeing wont be aligned with the world as Matter.js understands it.</p>
<p>To illustrate, let me return to Example 6.5. A lollipop is a compound body consisting of two parts, a rectangle (<code>this.part1</code>) and a circle (<code>this.part2</code>). Ive been drawing each lollipop by getting the positions for the two parts separately: <code>this.part1.position</code> and <code>this.part2.position</code>. However, the overall compound body also has a position, <code>this.body.position</code>. It would be tempting to use that as the position for drawing the rectangle, and to figure out the circles position manually using an offset. After all, thats how I conceived of the compound shape to begin with (look back at Figure 6.6).</p>
<pre class="codesplit" data-code-language="javascript"> show() {
let position = this.body.position;
let angle = this.body.angle;
push();
translate(position.x, position.y);
rotate(angle);
rect(0, 0, this.w, this.h);
circle(0, this.h / 2, this.r * 2);
pop();
}</pre>
<p>Figure 6.7 shows the result of this change. (In the online version, you can toggle the correct and incorrect rendering by clicking the mouse.)</p>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/HWeBLcNuu" data-example-path="examples/06_libraries/6_5_compound_bodies_error"><img src="examples/06_libraries/6_5_compound_bodies_error/screenshot.png"></div>
<figcaption>Figure 6.7 What happens when the shapes are drawn differently than how they were configured for Matter.js</figcaption>
</figure>
<p>At first glance, this new version may look fine, but if you look closer, the collisions are off and the shapes overlap in odd ways. This isnt because the physics are broken; its because Im not communicating properly between p5.js and Matter.js. It turns out the overall body position isnt the center of the rectangle, but rather the “center of mass” between the rectangle and the circle. Matter.js is calculating the physics and managing collisions as before, but Im drawing each body in the wrong place!</p>
<div data-type="exercise">
<h3 id="exercise-64">Exercise 6.4</h3>
<p>Make your own little alien being using multiple shapes attached to a single body. Remember, you arent limited to using the basic shape-drawing functions in p5.js; you can use images and colors, add hair with lines, and more. Think of the Matter.js shapes as skeletons for your original fantastical design!</p>
</div>
<h2 id="feeling-attached-matterjs-constraints">Feeling Attached: Matter.js Constraints</h2>
<p>A Matter.js <strong><em>constraint</em></strong> is a mechanism to connect one body to another, enabling simulations of swinging pendulums, elastic bridges, squishy characters, wheels spinning on an axle, and more. There are three kinds of constraints: distance constraints and revolute constraints, both managed through the <code>Constraint</code> class, and mouse constraints, managed through the <code>MouseConstraint</code> class.</p>
<h3 id="distance-constraints">Distance Constraints</h3>
<figure class="half-width-right">
<img src="images/06_libraries/06_libraries_10.png" alt="Figure 6.8: A constraint is a connection between two bodies at an anchor point for each body.">
<figcaption>Figure 6.8: A constraint is a connection between two bodies at an anchor point for each body.</figcaption>
</figure>
<p>A <strong>distance constraint</strong> is a connection of fixed length between two bodies. The constraint is attached to each body at a specified <strong>anchor</strong>, a point relative to the bodys center (see Figure 6.8). Depending on the constraints stiffness, the “fixed” length of the constraint can exhibit variability.</p>
<p>Defining a constraint uses a similar methodology as creating bodies, only you need to have two bodies ready to go. Lets assume there are two <code>Particle</code> objects that each store a reference to a Matter.js body in a property called <code>body</code>. Ill call them <code>particleA</code> and <code>particleB</code>.</p>
<pre class="codesplit" data-code-language="javascript">let particleA = new Particle();
let particleB = new Particle();</pre>
<p>I want to create a constraint between these particles. For that, I need to define a series of options that determine the constraints behavior:</p>
<ul>
<li><code>bodyA</code>: The first body that the constraint connects, establishing one end of the constraint.</li>
<li><code>bodyB</code>: The second body that the constraint connects, forming the other end.</li>
<li><code>pointA</code>: The position, relative to <code>bodyA</code>, where the constraint is anchored to the first body.</li>
<li><code>pointB</code>: The position, relative to <code>bodyB</code>, where the constraint is anchored to the second body.</li>
<li><code>length</code>: The resting or target length of the constraint. The constraint will attempt to maintain this length during the simulation.</li>
<li><code>stiffness</code>: A value between 0 and 1 that represents the rigidity of the constraint, with 1 being fully rigid and 0 being completely soft.</li>
</ul>
<p>These settings all get packaged up in an object literal.</p>
<pre class="codesplit" data-code-language="javascript">let options = {
bodyA: particleA.body,
bodyB: particleB.body,
pointA: Vector.create(0, 0),
pointB: Vector.create(0, 0),
length: 100,
stiffness: 0.5
}</pre>
<p>Technically, the only required options are <code>bodyA</code> and <code>bodyB</code>, the two bodies connected by the constraint. If you dont specify any additional options, Matter.js will choose defaults for the other properties. For example, it will use <code>(0, 0)</code> for each relative anchor point (the bodys center), set the <code>length</code> to the current distance between the bodies, and assign a default <code>stiffness</code> of <code>0.7</code>. Two other notable options I didnt include are <code>damping</code> and <code>angularStiffness</code>. The <code>damping</code> option affects the constraints resistance to motion, with higher values causing the constraint to lose energy more quickly. The <code>angularStiffness</code> option controls the rigidity of the constraints angular motion, with higher values resulting in less angular flexibility between the bodies.</p>
<p>Once the options are configured, the constraint can be created. As usual, this assumes another alias: <code>Constraint</code> is equal to <code>Matter.Constraint</code>.</p>
<pre class="codesplit" data-code-language="javascript">let constraint = Constraint.create(options);
//{!1} Don't forget to add the constraint to the world!
Composite.add(engine.world, constraint);</pre>
<p>I can include a constraint to a class to encapsulate and manage the relationship between multiple bodies. Heres an example of a class that represents a swinging pendulum (mirroring Example 3.x from Chapter 3).</p>
<div data-type="example">
<h3 id="example-66-matterjs-pendulum">Example 6.6: Matter.js Pendulum</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/YT6u0GqtH" data-example-path="examples/06_libraries/6_6_matter_js_pendulum"><img src="examples/06_libraries/6_6_matter_js_pendulum/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">class Pendulum {
constructor(x, y, len) {
this.r = 12;
this.len = len;
//{!2} Create two bodies, one for the anchor and one for the bob.
// The anchor is static.
this.anchor = Bodies.circle(x, y, this.r, { isStatic: true });
this.bob = Bodies.circle(x + len, y, this.r, { restitution: 0.6 });
//{!6} Create a constraint connecting the anchor and bob
let options = {
bodyA: this.anchor,
bodyB: this.bob,
length: this.len,
};
this.arm = Matter.Constraint.create(options);
//{!3} Add all bodies and constraints to the world.
Composite.add(engine.world, this.anchor);
Composite.add(engine.world, this.bob);
Composite.add(engine.world, this.arm);
}
show() {
fill(127);
stroke(0);
strokeWeight(2);
//{!1} Draw a line representing the pendulum arm.
line(this.anchor.position.x, this.anchor.position.y, this.bob.position.x, this.bob.position.y);
//{!6} Draw the anchor.
push();
translate(this.anchor.position.x, this.anchor.position.y);
rotate(this.anchor.angle);
circle(0, 0, this.r * 2);
line(0, 0, this.r, 0);
pop();
//{!6} Draw the bob.
push();
translate(this.bob.position.x, this.bob.position.y);
rotate(this.bob.angle);
circle(0, 0, this.r * 2);
line(0, 0, this.r, 0);
pop();
}
}</pre>
<p>Example 6.6 uses a default <code>stiffness</code> of <code>0.7</code>. If you try a lower value, the pendulum will appear more like a soft spring.</p>
<div data-type="exercise">
<h3 id="exercise-65">Exercise 6.5</h3>
<p>Create a simulation of a bridge by using constraints to connect a sequence of circles (or rectangles) as shown below. Use the <code>isStatic</code> property to lock the endpoints in place. Experiment with different values to make the bridge more or less “springy.” The joints themselves have no physical geometry, so in order for your bridge not to have holes, spacing between the nodes will be important.</p>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/7U7yrrbNz" data-example-path="examples/06_libraries/exercise_6_5_bridge"><img src="examples/06_libraries/exercise_6_5_bridge/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<h3 id="revolute-constraints">Revolute Constraints</h3>
<figure class="half-width-right">
<img src="images/06_libraries/06_libraries_11.png" alt="Figure 6.9: A revolute constraint is a connection between two bodies at a single anchor point or hinge.">
<figcaption>Figure 6.9: A revolute constraint is a connection between two bodies at a single anchor point or hinge.</figcaption>
</figure>
<p>Another kind of connection between bodies common to physics engines is a <strong>revolute joint</strong>. This type of constraint connects two bodies at a common anchor point, also known as a <strong>hinge</strong> (see Figure 6.9). While there isnt a separate revolute constraint in Matter.js, you can make one with a regular <code>Constraint</code> of length zero. This way the bodies can rotate around a common anchor point.</p>
<p>The first step is to create the connected bodies. For a first example, Id like to create a spinning rectangle (akin to a propellor or windmill) in a fixed position. For this case, I only need one body connected to a “point.” This simplifies things, since I dont have to worry about collisions between the two bodies connected at a hinge.</p>
<pre class="codesplit" data-code-language="javascript">// Create a body at a given x,y with a width and height
let body = Bodies.rectangle(x, y, w, h);
Composite.add(engine.world, body);</pre>
<p>Next, I can create the constraint. With a <code>length</code> of <code>0</code>, it needs a <code>stiffness</code> of <code>1</code>, otherwise the constraint may not be stable enough to keep the body connected at the anchor point.</p>
<pre class="codesplit" data-code-language="javascript">// The constraint connects the body to a fixed x,y position with a length of 0 and stiffness of 1.
let options = {
bodyA: this.body,
pointB: { x, y },
length: 0,
stiffness: 1,
};
// Create the constraint and add it to the world.
let constraint = Matter.Constraint.create(options);
Composite.add(engine.world, constraint);</pre>
<p>Putting it together, Ill write a sketch with a class called <code>Windmill</code> representing a rotating body. The sketch also includes a <code>Particle</code> class for dropping particles onto the windmill.</p>
<div data-type="example">
<h3 id="example-67-spinning-windmill">Example 6.7: Spinning Windmill</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/D96JFWc3-" data-example-path="examples/06_libraries/6_7_windmill"><img src="examples/06_libraries/6_7_windmill/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">class Windmill {
constructor(x, y, w, h) {
this.w = w;
this.h = h;
//{!2) The rotating body
this.body = Bodies.rectangle(x, y, w, h);
Composite.add(engine.world, this.body);
//{!8} The "revolute" constraint
let options = {
bodyA: this.body,
pointB: { x, y },
length: 0,
stiffness: 1,
};
this.constraint = Matter.Constraint.create(options);
Composite.add(engine.world, this.constraint);
}
show() {
rectMode(CENTER);
fill(127);
stroke(0);
strokeWeight(2);
push();
translate(this.body.position.x, this.body.position.y);
push();
rotate(this.body.angle);
rect(0, 0, this.w, this.h);
pop();
//{!1} Draw a stand for the windmill (not part of the physics)
line(0, 0, 0, height);
pop();
}
}</pre>
<p>Notice the line in this example representing the windmill stand. It isnt part of the Matter.js physics world, and I never created a body for it. This illustrates an important point about working with a physics engine alongside p5.js: you can add elements to the canvas that contribute to the visual design without affecting the physics, as long as you dont need those elements to participate in the simulation itself.</p>
<div data-type="exercise">
<h3 id="exercise-66">Exercise 6.6</h3>
<figure>
<img src="images/06_libraries/06_libraries_12.png" alt="">
<figcaption></figcaption>
</figure>
<p>Create a vehicle that has revolute joints for its wheels. Consider the size and positioning of the wheels. How does changing the <code>stiffness</code> property affect their movement?</p>
<figure>
<img src="images/06_libraries/06_libraries_13.png" alt="">
<figcaption></figcaption>
</figure>
</div>
<h3 id="mouse-constraints">Mouse Constraints</h3>
<p>Before I introduce the <code>MouseConstraint</code> class, consider the following question: how do you set the position of a Matter.js body to the mouse position? More to the point, why would you need a constraint for this? After all, you have access to the bodys position, and you have access to the mouses position. Whats wrong with assigning one to the other?</p>
<pre class="codesplit" data-code-language="javascript">body.position.x = mouseX;
body.position.y = mouseY;</pre>
<p>While this will in fact move the body, it will also have the unfortunate result of breaking the physics. Imagine youve built a teleportation machine that allows you to move instantly from your bedroom to your kitchen (good for late-night snacking). Thats easy enough to imagine, but now go ahead and rewrite Newtons laws of motion to account for the possibility of teleportation. Not so easy anymore, is it?</p>
<p>Matter.js has the same problem. If you manually assign the position of a body, its like saying “teleport that body,” and Matter.js no longer knows how to compute the physics properly. However, Matter.js <em>does</em> allow you to tie a string around your waist and have a friend of yours to stand in the kitchen and drag you there. Replace your friend with your mouse, and thats what a mouse constraint is.</p>
<p>Imagine that the moment you click the mouse over a shape, the mouse attaches to that body with a string. Now you can move the mouse around and it will drag the body around with it, until you release the mouse. This works in a similar fashion as a revolute joint in that you can set the length of that “string” to 0, effectively moving a shape with the mouse.</p>
<p>Before you can attach the mouse, however, you need to create a Matter.js <code>Mouse</code> object that listens for mouse interactions with the p5.js canvas.</p>
<pre class="codesplit" data-code-language="javascript">// Aliases for Matter.js Mouse and MouseConstraint
let { Mouse, MouseConstraint } = Matter;
// Need a reference to the p5.js canvas to listen for mouse
let canvas = createCanvas(640, 240);
// Create a Matter mouse attached to the native HTML5 canvas element
let mouse = Mouse.create(canvas.elt);</pre>
<p>Next, use the <code>mouse</code> object to create a <code>MouseConstraint</code>.</p>
<pre class="codesplit" data-code-language="javascript">let mouseConstraint = MouseConstraint.create(engine, { mouse });
Composite.add(engine.world, mouseConstraint);</pre>
<p>This will instantly allow you to interact with all Matter.js bodies via the mouse. Theres no need to explicitly attach the constraint to a particular body; any body you click will be constrained to the mouse.</p>
<p>You can also configure all the usual constraint variables by adding a <code>constraint</code> property to the options passed into the <code>MouseConstraint.create()</code> method.</p>
<pre class="codesplit" data-code-language="javascript">mouse = Mouse.create(canvas.elt);
let options = {
mouse,
//{!1} Customize the constraint with additional properties
constraint: { stiffness: 0.7 }
};
mouseConstraint = MouseConstraint.create(engine, options);
Composite.add(engine.world, mouseConstraint);</pre>
<p>Heres an example demonstrating a <code>MouseConstraint</code> with two <code>Box</code> objects. There are also static bodies acting as walls around the borders of the canvas.</p>
<div data-type="example">
<h3 id="example-68-mouseconstraint-demonstration">Example 6.8: MouseConstraint Demonstration</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/mTRKgn44p" data-example-path="examples/06_libraries/6_8_mouse_constraint"><img src="examples/06_libraries/6_8_mouse_constraint/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<p>In the example, you'll see that the <code>stiffness</code> property of the constraint is set to <code>0.7</code>, giving a bit of elasticity to the imaginary mouse string. Other properties such as <code>angularStiffness</code> and <code>damping</code> can also influence the mouse's interaction. Play around with these values. What happens if you adjust the stiffness?</p>
<h2 id="bringing-it-all-back-home-to-forces">Bringing It All Back Home to Forces</h2>
<p>In Chapter 2, I covered how to build an environment where there are multiple forces at play. An object might respond to gravitational attraction, wind, air resistance, and so on. Clearly, there are forces at work in Matter.js as rectangles and circles spin and fly around the screen! But so far, Ive only actually demonstrated how to manipulate a single global force: gravity.</p>
<pre class="codesplit" data-code-language="javascript"> let engine = Engine.create();
// Changing the engine's gravity to point horizontally
engine.gravity.x = 1;
engine.gravity.y = 0;</pre>
<p>If I want to use any of the Chapter 2 techniques with Matter.js, I need look no further than the trusty <code>applyForce()</code> method. In Chapter 2, I wrote this method as part of the <code>Mover</code> class. It received a vector, divided it by mass, and accumulated it into the movers 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 <code>Body.applyForce()</code>. Heres what that looks like in whats now the <code>Box</code> class.</p>
<pre class="codesplit" data-code-language="javascript">class Box {
applyForce(force) {
//{!1} Calling Body's applyForce() function
Body.applyForce(this.body, this.body.position, force);
}
}</pre>
<p>Here, the <code>Box</code> classs <code>applyForce()</code> method receives a force vector and simply passes it along to Matter.jss <code>applyForce()</code> 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 movers center. Here, the exact position on the body where the force is applied is specified. In this case, Ive just applied it to the center as before by asking the body for its position, but this could be adjusted. For example, imagine a scenario where a force pushes at the edge of a box, causing it to spin across the canvas, much like dice tumbling when thrown.</p>
<p>How can I bring forces into a Matter-driven sketch? Say I want to use a gravitational attraction force. Remember the code from Example 2.6 in the <code>Attractor</code> class?</p>
<pre class="codesplit" data-code-language="javascript"> attract(mover) {
let force = p5.Vector.sub(this.position, mover.position);
let distance = force.mag();
distance = constrain(distance, 5, 25);
let strength = (G * this.mass * mover.mass) / (distance * distance);
force.setMag(strength);
return force;
}</pre>
<p>I can rewrite the exact same method using <code>Matter.Vector</code> and incorporate it into a new <code>Attractor</code> class.</p>
<div data-type="example">
<h3 id="example-69-attraction-with-matterjs">Example 6.9 Attraction with Matter.js</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/16sblEvax" data-example-path="examples/06_libraries/6_9_matter_js_attraction"><img src="examples/06_libraries/6_9_matter_js_attraction/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">class Attractor {
constructor(x, y) {
// {!3} The attractor is a static Matter.js body.
this.radius = 32;
this.body = Bodies.circle(x, y, this.radius, { isStatic: true });
Composite.add(engine.world, this.body);
}
attract(mover) {
//{!2} The attract method now uses Matter.js Vector functions.
let force = Vector.sub(this.body.position, mover.body.position);
let distance = Vector.magnitude(force);
distance = constrain(distance, 5, 25);
//{!1} Using a small value for G keeps the system stable.
let G = 0.02;
//{!1} While the mover's mass can be accessed, because the attractor is a "static" body its mass will be infinity, so it is ignored here.
let strength = (G * mover.body.mass) / (distance * distance);
//{!2} More Matter.js Vector functions
force = Vector.normalise(force);
force = Vector.mult(force, strength);
return force;
}
}</pre>
<p>In addition to writing a custom <code>attract()</code> method for Example 6.9, there are two other key elements required for the sketch to behave more like the example from Chapter 2. First, remember that a Matter.js <code>Engine</code> has a default gravity pointing down. I nee to disable it in <code>setup()</code> with a <code>(0, 0)</code> vector.</p>
<pre class="codesplit" data-code-language="javascript">engine = Engine.create();
//{!1} Disabling default gravity
engine.gravity = Vector.create(0, 0);</pre>
<p>Second, bodies in Matter.js are created with a default air resistance that causes them to slow down as they move. I need to set this to <code>0</code> as well to simulate the bodies being in the “vacuum” of space.</p>
<pre class="codesplit" data-code-language="javascript">class Mover {
constructor(x, y, radius) {
this.radius = radius;
//{!1} Disabling default air resistance
let options = { frictionAir: 0 };
this.body = Bodies.circle(x, y, this.radius, options);
}</pre>
<p>This is also a good time to revisit to the concept of mass. Although I'm accessing the <code>mass</code> property of the body associated with the mover in the <code>attract()</code> method, I never explicitly set it. In Matter.js, the mass of a body is automatically calculated based on its size (area) and density. Larger bodies will therefore have a greater mass. To increase the mass relative to the size, you can try setting a <code>density</code> property in the <code>options</code> object (the default is <code>0.001</code>). For static bodies, such as the attractor, the mass is considered infinite. This is how the attractor stays locked in position despite the movers continuously knocking into it.</p>
<div data-type="exercise">
<h3 id="exercise-67">Exercise 6.7</h3>
<p>Incorporate <code>Body.applyForce()</code> into a new <code>spin()</code> method for Example 6.7s <code>Windmill</code> class to simulate a motor continuously rotating the windmill.</p>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/cN6zF325F" data-example-path="examples/06_libraries/exercise_6_7_windmill_motor"><img src="examples/06_libraries/exercise_6_7_windmill_motor/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<div data-type="exercise">
<h3 id="exercise-68">Exercise 6.8</h3>
<p>Convert any of the steering behavior examples from Chapter 5 to Matter.js. What does flocking look like with collisions?!</p>
</div>
<h2 id="collision-events">Collision Events</h2>
<p>This book isnt called <em>The Nature of Matter.js</em>, so Im not going to cover every single possible feature of the Matter.js library. At this point, Ive gone over the basics of creating bodies and constraints, and shown you some of what the library can do. With the skills youve gained, hopefully the learning process will be considerably less painful when it comes time to use an aspect of Matter.js that I havent addressed here. Before moving on, however, theres one more feature of the library that I think is worth covering: collision events.</p>
<p>Heres a question youve likely been wondering about: “What if I want something extra to happen when two bodies collide? I mean, dont get me wrong—Im thrilled that Matter.js is handling all of the collisions behind the scenes. But if its taking care of the collisions for me, how am I supposed to know when theyre happening?”</p>
<p>Your first thoughts to answer this question might be as follows: “Well, I know all the bodies in the system, and I know where theyre all located. I can just start comparing the bodies positions and see which ones are intersecting. Then I can do something extra for the bodies that are determined to be colliding.”</p>
<p>Thats a nice thought, but hello??!? The whole point of using a physics engine like Matter.js is that it will take care of all that work for you. If youre going to implement the computational geometry algorithms to test for intersection, then youre basically implementing your own Matter.js!</p>
<p>Of course, wanting to know when bodies are colliding is a pretty common problem, so Matter.js has anticipated it. It can alert you to moments of collision with an <strong>event listener</strong>. If youve worked with mouse or keyboard interaction in p5.js, you already have experience with event listeners. Consider the following:</p>
<pre class="codesplit" data-code-language="javascript">// A mousePressed event you've probably written many times before.
function mousePressed() {
print("The mouse was pressed!");
}</pre>
<p>The global <code>mousePressed()</code> function in p5.js is executed whenever the mouse is pressed. This is known as a <strong><em>callback</em></strong>, a function thats “called back” at a later time when an event occurs. Matter.js collision events operate in a similar fashion. Instead of p5.js just knowing to look for a function called <code>mousePressed()</code> when a mouse event occurs, however, you have to explicitly define the name for a Matter.js collision callback.</p>
<pre class="codesplit" data-code-language="javascript">Matter.Events.on(engine, 'collisionStart', handleCollisions);</pre>
<p>This code specifies that a function named <code>handleCollisions</code> should be executed whenever a collision between two bodies starts. There are also events for <code>'collisionActive'</code> (executed over and over for the duration of an ongoing collision) and <code>'collisionEnd'</code>(executed when two bodies stop colliding), but for a basic demonstration, knowing when the collision begins is more than adequate.</p>
<p>Much like <code>mousePressed()</code> is triggered when the mouse is pressed, <code>handleCollisions()</code> (or whatever you choose to name the callback function) is triggered when two shapes collide. It can be written as follows:</p>
<pre class="codesplit" data-code-language="javascript">function handleCollisions(event) {
}</pre>
<p>Notice that the function includes an <code>event</code> parameter. This is an object that includes all the data associated with a collision (or multiple collisions if more than one has occurred in that time step), such as which bodies are involved. Matter.js automatically creates this object and passes it along to the <code>handleCollisions()</code> callback every time theres a collision.</p>
<p>Say I have a sketch with <code>Particle</code> objects that each store a reference to a Matter.js body, and I want the particles to change color when they collide with each other. Heres the process to follow to make that happen.</p>
<p><strong>Step 1: Event, could you tell me what two things collided?</strong></p>
<p>Now, what has collided here? Matter.js detects collisions between a “pair” of bodies, these are the objects that have geometry. Any pair of colliding bodies will be in an array called <code>pairs</code> inside the <code>event</code> object. Inside <code>handleCollisions()</code>, I can use a <code>for…of</code> loop to iterate over those pairs.</p>
<pre class="codesplit" data-code-language="javascript">for (let pair of event.pairs) {
}
</pre>
<p><strong>Step 2: Pair, could tell me which two bodies you include?</strong></p>
<p>Each pair in the <code>pairs</code> array is an object with references to the two bodies involved in the collision, <code>bodyA</code> and <code>bodyB</code>. Ill extract those bodies.</p>
<pre class="codesplit" data-code-language="javascript">for (let pair of event.pairs) {
let bodyA = pair.bodyA;
let bodyB = pair.bodyB;
}</pre>
<p><strong>Step 3: Bodies, could you tell me which Particles youre associated with?</strong></p>
<p>Getting from the relevant Matter.js bodies to the <code>Particle</code> objects theyre associated with is a little harder. After all, Matter.js doesnt know anything about my code. Sure, its doing all sorts of stuff to keep track of the relationships between bodies and constraints, but its up to me to manage my own objects and their associations with Matter.js elements. That said, every Matter.js body is instantiated with an empty object— <code>{ }</code>— called <code>plugin</code>, ready to store any custom data about that body. I can link the body to a custom object (in this case, a <code>Particle</code>) by storing a reference to that object in the <code>plugin</code> property.</p>
<p>Take a look at the updated constructor in the <code>Particle</code> class where the body is made. Note how the body-making procedure has been expanded by one line of code to add a <code>particle</code> property inside <code>plugin</code>. Its important to make sure youre adding a new property to the existing <code>plugin</code> objet (in this case, <code>plugin.particle = this</code>) rather than overwriting the <code>plugin</code>object itself (for example, with <code>plugin = this</code>). That latter could interfere with other features or customizations.</p>
<pre class="codesplit" data-code-language="javascript">class Particle {
constructor(x, y, radius) {
this.radius = radius;
this.body = Bodies.circle(x, y, this.radius);
//{!1 .bold} "this" refers to this Particle object, telling the matter.js Body to store a
// reference to this Particle that can be accessed later
this.body.plugin.particle = this;
Composite.add(engine.world, this.body);
}</pre>
<p>Later, in the <code>handleCollision()</code> callback function, that <code>Particle</code> object can be access from the <code>Body</code> itself via the <code>plugin</code>.</p>
<div data-type="example">
<h3 id="example-610-collision-events">Example 6.10: Collision Events</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/3cREe4udP" data-example-path="examples/06_libraries/6_10_collision_events"><img src="examples/06_libraries/6_10_collision_events/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">function handleCollisions(event) {
for (let pair of event.pairs) {
let bodyA = pair.bodyA;
let bodyB = pair.bodyB;
//{!2} Retrieving the particles associated with the colliding bodies via the plugin.
let particleA = bodyA.plugin.particle;
let particleB = bodyB.plugin.particle;
//{!4} If they are both particles, change their color!
if (particleA instanceof Particle &#x26;&#x26; particleB instanceof Particle) {
particleA.change();
particleB.change();
}
}
}</pre>
<p>In most cases, you cant assume that the objects that collided are all <code>Particle</code> objects. After all, the particle might have collided with a <code>Boundary</code> object (or some other kind of thing, depending on whats in your world). You can check an objects “type” with JavaScripts <code>instanceof</code> operator, as Ive done in this example.</p>
<div data-type="exercise">
<h3 id="exercise-69">Exercise 6.9</h3>
<p>Create a simulation in which <code>Particle</code> objects disappear when they collide with one another. Where and how should you delete the particles? Can you have them shatter into smaller particles?</p>
</div>
<h2 id="a-brief-interlude-integration-methods">A Brief Interlude: Integration Methods</h2>
<p>Has this ever happened to you? Youre at a fancy cocktail party, regaling your friends with tall tales of your incredible software physics simulations. Suddenly, out of the blue, someone pipes up: “Enchanting! But what integration method are you using?”</p>
<p>“What?!” you think to yourself. “Integration???”</p>
<p>Maybe youve heard the term before. Along with differentiation, its one of the two main operations in calculus. Oh right, calculus.</p>
<p>Ive managed to get most of the way through the material in this book related to physics simulation without really needing to dive into calculus. As I wrap up the first half of this book, however, its worth taking a moment to examine the calculus behind what Ive been demonstrating and how it relates to the methodology in certain physics libraries (like Box2D, Matter.js, and the upcoming toxiclibs). This way youll know what to say at the next cocktail party when someone asks you about integration.</p>
<p>Ill begin with a question: “What does integration have to do with position, velocity, and acceleration?” To answer, I should first define <strong>differentiation</strong>, the process of finding a derivative. The <strong>derivative</strong> of a function is a measure of how a function changes over time. Consider position and its derivative. Position is a point in space, while velocity is the change in position over time. Therefore, velocity can be described as the derivative of position. And whats acceleration? The change in velocity over time. Acceleration is the derivative of velocity.</p>
<p><strong>Integration</strong>, the process of finidng an integral, is the inverse of differentiation. For example, the <strong>integral</strong> of an objects velocity over time tells us the objects new position when that time period ends. Position is the integral of velocity, and velocity is the integral of acceleration.</p>
<p>Since the physics simulations in this book are founded on the notion of calculating acceleration based on forces, integration is needed to figure out where the object is after a certain period of time (like one cycle of the <code>draw()</code> loop). I other words, youve been doing integration all along! It looks like this:</p>
<pre class="codesplit" data-code-language="javascript">velocity.add(acceleration);
position.add(velocity);</pre>
<p>This methodology is known as <strong>Euler integration</strong> (named for the mathematician Leonhard Euler, pronounced “Oiler”), or the <strong>Euler method</strong>. Its essentially the simplest form of integration, and its very easy to implement in code—just two lines! However, while it's computationally simple, it is by no means the most accurate or stable choice for certain types of simulations.</p>
<p>Why is Euler inaccurate? Think about it this way: when you bounce down a sidewalk on a pogo stick, does the pogo stick sit in one position at time equals 1 second, then disappear and suddenly reappear in a new position at time equals 2 seconds, and do the same thing for 3 seconds, and 4, and 5? No, of course not. The pogo stick moves continuously through time. But whats happening in a p5.js sketch? A circle is at one position at frame 0, another at frame 1, another at frame 2, and so on. Sure, at 30 frames per second, you see the <em>illusion</em> of motion. But a new position is only computed every <span data-type="equation">N</span> units of time, whereas the real world is perfectly continuous. This results in some inaccuracies, as shown in Figure 6.10.</p>
<figure>
<img src="images/06_libraries/06_libraries_14.png" alt="Figure 6.10: The Euler approximation of a curve">
<figcaption>Figure 6.10: The Euler approximation of a curve</figcaption>
</figure>
<p>The “real world” is the smooth curve; the Euler simulation is the series of straight line segments. One option to improve on Euler is to use smaller time steps—instead of once per frame, you could recalculate an objects position 20 times per frame. But this isnt practical; the sketch might then run too slowly.</p>
<p>I still believe that Euler is the best method for learning the basics, and its also perfectly adequate for most of the projects you might want to make with p5.js. Anything lost in efficiency or inaccuracy is made up for in ease of use and understandability. For better accuracy, for example, the Box2D engine uses something called symplectic Euler or semi-explicit Euler, a slight modification of Euler. Other engines use an integration method called Runge-Kutta (named for German mathematicians C. Runge and M. W. Kutta) physics engines.</p>
<p>Another very popular integration method used in physics libraries, including both Matter.js and toxiclibs.js, is known as <strong>Verlet integration</strong>. A simple way to describe Verlet integration is to think of the typical motion algorithm without explicitly storing velocity. After all, you dont really need to store the velocity; if you always know where an object was at one point in time and where it is now, you can extrapolate its velocity. Verlet integration does precisely this, calculating velocity on the fly while the program is running, instead of maintaining a separate velocity variable.</p>
<p>Verlet integration is particularly well suited for particle systems, especially those with spring connections between the particles. Physics libraries hide the details from you so you dont have to worry about how it all works, but if youre interested in diving deeper into Verlet physics, I suggest reading the seminal paper on the topic, from which just about every Verlet computer graphics simulation is derived: <a href="http://www.cs.cmu.edu/afs/cs/academic/class/15462-s13/www/lec_slides/Jakobsen.pdf">“Advanced Character Physics” by Thomas Jackobsen</a>.</p>
<h2 id="verlet-physics-with-toxiclibsjs">Verlet Physics with toxiclibs.js</h2>
<blockquote data-type="epigraph">
<p><em>toxiclibs is an independent, open source library collection for computational design tasks with Java &#x26; Processing developed by Karsten “toxi” Schmidt. The classes are purposefully kept fairly generic in order to maximize re-use in different contexts ranging from generative design, animation, interaction/interface design, data visualization to architecture and digital fabrication, use as teaching tool and more. — </em><a href="http://toxiclibs.org/"><em>toxiclibs.org</em></a><em> (last seen October 2021).</em></p>
</blockquote>
<p>Around 2005, Karsten Schmidt began work on toxiclibs, a sweeping and pioneering open source library for computational design, specifically built for the Java version of Processing. Though it hasnt been actively maintained in over 10 years, the concepts and techniques that the library demonstrated can be found in countless creative coding projects today.</p>
<p>Schmidt continues to contribute to the creative coding field today through his recent project, <a href="https://thi.ng/umbrella">thi.ng/umbrella</a><strong>.</strong> This work can be considered an indirect successor to toxiclibs, but with a much greater scope and detail. If you like this book, you might especially enjoy exploring <a href="https://thi.ng/vectors">thi.ng/vectors</a>, which provides over 800 vector algebra functions using plain vanilla JavaScript arrays.</p>
<p>While <a href="http://thi.ng/umbrella">thi.ng/umbrella</a> may be a more modern and sophisticated approach, I find that toxiclibs remains a versatile tool, and I continue to use a version compatible with the latest version of Processing (4.1 as of the time of this writing). For this book, we should thank our lucky starts for <a href="http://haptic-data.com/toxiclibsjs">toxiclibs.js</a>, a JavaScript adaptation of the library, created by Kyle Phillips (”hapticdata”). Im only going to cover on a few examples related to Verlet physics, but toxiclibs.js includes a suite of other packages with functionality related to with, color, geometry, math, and more.</p>
<p>The examples Im about to demonstrate could also be created using Matter.js, but I've decided to move to toxiclibs for several reasons. The library holds a special place in my heart as a personal favorite, and its historically significant. I also believe that showing more than one physics library is important for providing a broader understanding of the tools and approaches available.</p>
<p>This switch from Matter to toxiclibs raises an important question, though: how should you decide which library to use for a project? Matter.js, or toxiclibs, or something else? If you fall into one of the following two categories, your decision is a bit easier:</p>
<p><strong>1. My project involves collisions. I have circles, squares, and other strangely shaped objects that knock each other around and bounce off each other. </strong>In this case, youre going to want to use Matter.js, since toxiclibs.js doesnt handle “rigid body” collisions.</p>
<p><strong>2. My project involves lots of particles flying around the screen. Sometimes they attract each other. Sometimes they repel each other. And sometimes theyre connected with springs. </strong>In this case, toxiclibs.js is likely your best choice. Its simpler to use in some ways than Matter.js and particularly well suited to connected systems of particles. Its also high performance, due to the speed of the Verlet integration algorithm (not to mention the fact that it gets to ignore all of the collision geometry).</p>
<p>Heres a little chart that covers some of the features for each physics library.</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Matter.js</th>
<th>toxiclibs.js</th>
</tr>
</thead>
<tbody>
<tr>
<td>rigid body collisions</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>3D physics</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>particle attraction and repulsion forces</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>spring connections (force-based)</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>constraints (general-purpose connections)</td>
<td>Yes</td>
<td>No</td>
</tr>
</tbody>
</table>
<p>All of the documentation and downloads for the library files can be found at the toxiclibs.js website: <a href="http://haptic-data.com/toxiclibsjs">http://haptic-data.com/toxiclibsjs</a>. For the examples in this book, Ill be working with a hosted CDN version of the library referenced in <em>index.html</em>, just as I demonstrated earlier for Matter.js. Heres the <code>&#x3C;script></code> element to add:</p>
<pre class="codesplit" data-code-language="html">&#x3C;script src="<a href="https://cdn.jsdelivr.net/gh/hapticdata/toxiclibsjs@0.3.2/build/toxiclibs.js">https://cdn.jsdelivr.net/gh/hapticdata/toxiclibsjs@0.3.2/build/toxiclibs.js</a>">&#x3C;/script></pre>
<p>My overview of Matter.js focused on a few key features of that library: world, vector, body, constraint. This has actually given you a head start on understanding toxiclibs.js as well, since it follows a similar structure. The following table shows the corresponding toxiclibs features.</p>
<table>
<thead>
<tr>
<th>Matter.js</th>
<th>toxiclibs.js</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>World</code></td>
<td><code>VerletPhysics2D</code></td>
</tr>
<tr>
<td><code>Vector</code></td>
<td><code>Vec2D</code></td>
</tr>
<tr>
<td><code>Body</code></td>
<td><code>VerletParticle2D</code></td>
</tr>
<tr>
<td><code>Constraint</code></td>
<td><code>VerletSpring2D</code></td>
</tr>
</tbody>
</table>
<p>Ill discuss how some of these features translate to toxclibs.js, before putting them together to create some interesting examples.</p>
<h3 id="vectors">Vectors</h3>
<p>Here we go again. Remember all that time spent learning the ins and outs of the <code>p5.Vector</code> class? Then remember how you had to revisit all those concepts with Matter.js and the <code>Matter.Vector</code> class? Well, its time to do it again, because toxiclibs.js also includes its own vector classes. It has one for two dimensions and one for three: <code>Vec2D</code> and <code>Vec3D</code>. These are both found in the <code>toxi.geom</code> package and can be aliased in the same manner as <code>Vector</code> with Matter.js.</p>
<pre class="codesplit" data-code-language="javascript">let { Vec2D, Vec3D } = toxi.geom;</pre>
<p>Once again, toxiclibs.js vectors are conceptually the same as the p5.js vectors we know and love, but they have their own style and syntax . Heres an overview of how some of the basic vector math operations from <code>p5.Vector</code> translated to <code>Vec2D</code>. (Im sticking with 2D to match the rest of this book, but I encourage you to explore 3D vectors as well.)</p>
<table>
<thead>
<tr>
<th>p5.Vector</th>
<th>Vec2D</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<pre class="codesplit" data-code-language="javascript">let a = createVector(1, -1);
let b = createVector(3, 4);
a.add(b);</pre>
</td>
<td>
<pre class="codesplit" data-code-language="javascript">let a = new Vec2D(1, -1);
let b = new Vec2D(3, 4);
a.addSelf(b);</pre>
</td>
</tr>
<tr>
<td>
<pre class="codesplit" data-code-language="javascript">let a = createVector(1, -1);
let b = createVector(3, 4);
let c = p5.Vector.add(a, b);</pre>
</td>
<td>
<pre class="codesplit" data-code-language="javascript">let a = new Vec2D(1, -1);
let b = new Vec2D(3, 4);
let c = a.add(b);</pre>
</td>
</tr>
<tr>
<td>
<pre class="codesplit" data-code-language="javascript">let a = createVector(1, -1);
let m = a.mag();
a.normalize();</pre>
</td>
<td>
<pre class="codesplit" data-code-language="javascript">let a = new Vec2D(1, -1);
let m = a.magnitude();
a.normalize();</pre>
</td>
</tr>
</tbody>
</table>
<p>Notice in particular how toxiclibs.js vectors are created by calling the <code>Vec2D</code> constructor with the <code>new</code> keyword, rather than by using a factory method like <code>Matter.Vector()</code> or <code>createVector()</code>.</p>
<h3 id="the-physics-world">The Physics World</h3>
<p>The classes to describe the world and its particles and springs in toxiclibs.js are found in <code>toxi.physics2d.</code> Im also going to use a <code>Rect</code> object (to describe a generic rectangle boundary) and <code>GravityBehavior</code> to apply a global gravity force to the world. Including <code>Vec2D</code>, I now have all the following class aliases.</p>
<pre class="codesplit" data-code-language="javascript">
// The necessary geometry classes for vectors and rectangles
let { Vec2D, Rect } = toxi.geom;
// Aliasing the important classes from toxi.physics2d
let { VerletPhysics2D, VerletParticle2D, VerletSpring2D } = toxi.physics2d;
// For the world's gravity
let { GravityBehavior } = toxi.physics2d.behaviors;</pre>
<p>The first step is to create the world.</p>
<pre class="codesplit" data-code-language="javascript">let physics;
function setup() {
// Creating a toxiclibs Verlet physics world
physics = new VerletPhysics2D();</pre>
<p>Once I have the <code>VerletPhysics</code> world, I can set global properties. For example, if I want a hard boundaries beyond which particles cant travel, I can provide a rectangular bounds.</p>
<pre class="codesplit" data-code-language="javascript"> physics.setWorldBounds(new Rect(0, 0, width, height));</pre>
<p>In addition, I can add gravity with the <code>GravityBehavior</code> object. A gravity behavior requires a vector—how strong and in what direction is the gravity?</p>
<pre class="codesplit" data-code-language="javascript"> physics.addBehavior(new GravityBehavior(new Vec2D(0, 0.5)));
}</pre>
<p>Finally, in order to calculate the physics of the world and move the worlds objects around, I have to call the worlds <code>update()</code> method. Typically this would happen once per frame in <code>draw()</code>.</p>
<pre class="codesplit" data-code-language="javascript">function draw() {
//{!1} This is the same as matter.js Engine.update()
physics.update();
}</pre>
<p>Now all that remains is to populate the world.</p>
<h3 id="particles">Particles</h3>
<p>The toxiclibs.js equivalent of a Matter.js body—a thing that exists in the world and experiences physics—is a <strong><em>particle</em></strong>, as represented by the <code>VerletParticle2D</code> class. However, unlike Matter.js bodies, toxiclibs particles dont store geometry.</p>
<p>How should I integrate toxiclibs.js particles into a p5.js sketch? In the Matter.js examples, I created my own class (called, say, <code>Particle</code>) and included a reference to a Matter.js body.</p>
<pre class="codesplit" data-code-language="javascript">class Particle {
constructor(x, y, r) {
this.body = Bodies.circle(x, y, r);
}
}</pre>
<p>This technique was somewhat redundant, since Matter.js itself keeps track of the bodies in its world. However, it allowed me to manage which body is which (and therefore how each body should be drawn) without having to rely on iterating through Matter.jss internal lists. I might take the same approach with toxiclibs.js, making my own <code>Particle</code> class that stores a reference to a <code>VerletParticle2D</code> object. This way Ill be able to give the particles custom properties and draw them however I want. Id probably write the code as follows:</p>
<pre class="codesplit" data-code-language="javascript">class Particle {
constructor(x, y, r) {
//{!1} A VerletParticle needs an initial x,y position, but it has no geometry, so the r is only used for drawing.
this.particle = new VerletParticle2D(x, y);
this.r = r;
}
show() {
fill(127);
stroke(0);
//{!1} When it comes time to draw the particle, the x,y is stored in this.particle
circle(this.particle.x, this.particle.y, this.r * 2);
}
}</pre>
<p>Looking over this code, you might first notice that drawing the particle is as simple as grabbing the <code>x</code> and <code>y</code> properties and using them with <code>circle()</code>. Second, you might notice that this <code>Particle</code> class doesnt do much beyond storing a reference to a <code>VerletParticle2D</code> object. This hints at something important. Think back to the discussion of inheritance in Chapter 4, and then ask yourself: what is a <code>Particle</code> object other than an “augmented” <code>VerletParticle2D</code> object? Why bother making two objects—a <code>Particle</code> and a <code>VerletParticle2D</code>—for every one particle in the world, when I could simply extend the <code>VerletParticle2D</code> class to include the extra code needed to draw the particle?</p>
<pre class="codesplit" data-code-language="javascript">class Particle extends VerletParticle2D {
constructor(x, y, r) {
//{!1} Calling super() with x,y so that the object is initialized properly
super(x, y);
//{!1} Adding a variable to track radius
this.r = r;
}
//{!1} Augmenting by adding a show() method.
show() {
fill(127);
stroke(0);
//{!1} x and y from VerletParticle2D!
circle(this.x, this.y, this.r * 2);
}
}</pre>
<p>Furthermore, at the risk of blowing your mind, it turns out that the <code>VerletParticle2D</code> class is a subclass of <code>Vec2D</code>. This means that in addition to inheriting everything from <code>VerletParticle2D</code>, the <code>Particle</code> class has actually inherited all of the<code>Vec2D</code> methods as well!</p>
<p>I can now create new particles:</p>
<pre class="codesplit" data-code-language="javascript">let particle = new Particle(width/2, height/2, 8);</pre>
<p>Just creating a particle isnt enough, however. Much like in Matter.js, I have to explicitly add the new particle to the world. In toxiclibs.js, this is ddone with the <code>addParticle()</code> method.</p>
<pre class="codesplit" data-code-language="javascript">physics.addParticle(particle);</pre>
<p>If you look at the toxiclibs.js documentation youll see that <code>addParticle()</code> expects a <code>VerletParticle2D</code> object. But Ive passed it a <code>Particle</code> object. Does that work?</p>
<p>Yes! Remember one of the tenets of object-oriented programming: polymorphism. Here, because the <code>Particle</code> class extends <code>VerletParticle2D</code>, I can treat the particle in two different ways—as a <code>Particle</code> or as a <code>VerletParticle2D</code>. This is an incredibly powerful feature of object-oriented programming. If you build custom classes that inherit from toxiclibs.js classes, you can use the objects of those classes in conjunction with all of the methods toxiclibs.js has to offer.</p>
<h3 id="springs">Springs</h3>
<p>In addition to the <code>VerletParticle2D</code> class, toxiclibs.js has a set of classes that allow you to connect particles with spring forces. There are three types of springs in toxiclibs:</p>
<ul>
<li><code>VerletSpring2D</code>: A springy connection between two particles. The springs properties can be configured in such a way as to create a stiff, stick-like connection or a highly elastic, stretchy connection. A particle can also be locked so that only one end of the spring can move.</li>
<li><code>VerletConstrainedSpring2D</code>: A spring whose maximum distance can be limited. This can help the whole spring system achieve better stability.</li>
<li><code>VerletMinDistanceSpring2D</code>: A spring that only enforces its rest length if the current distance is less than its rest length. This is handy if you want to ensure objects are at least a certain distance from each other, but dont care if the distance is bigger than the enforced minimum.</li>
</ul>
<p>Inheritance and polymorphism once again prove to be useful when making springs. A spring expects two <code>VerletParticle2D</code> objects when its created, but as before, two <code>Particle</code> objects will do, since <code>Particle</code> extends<strong><em> </em></strong><code>VerletParticle2D</code>.</p>
<p>Heres some example code to create a spring. This snippet assumes the existence of two particles, <code>particle1</code> and <code>particle2</code>, and creates a connection between them with a given rest length and strength.</p>
<pre class="codesplit" data-code-language="javascript">//{!1} What is the rest length of the spring?
let length = 80;
//{!1} How strong is the spring? (The higher the value, the more rigid the spring.)
let strength = 0.01;
let spring = new VerletSpring2D(particle1, particle2, length, strength);</pre>
<p>Just as with particles, in order for the connection to actually be part of the physics world, it must be explicitly added to the world.</p>
<pre class="codesplit" data-code-language="javascript">physics.addSpring(spring);</pre>
<p>I have almost everything I need to build a simple first toxiclibs example: two particles connected to form a springy pendulum. Theres one more element I want to add, however: mouse interactivity.</p>
<p>With Matter.js, I explained that the physics simulation breaks down if you manually override a bodys position by setting it to the mouse. With toxiclibs, this isnt a problem. If I want to, I can set a particles <span data-type="equation">(x, y)</span> position manually. However, before doing so, its generally a good idea to call the particles <code>lock()</code> method, which fixes the particle in place. This is identical to setting the <code>isStatic</code> property to <code>true</code> in Matter.js.</p>
<p>The idea is to lock the particle temporarily so it stops responding to the worlds physics, alter its position, and then unlock it (with the <code>unlock()</code> method) so it can start moving again from its new location. For example, consider the scenario where I want to reposition a particle whenever the mouse is pressed.</p>
<pre class="codesplit" data-code-language="javascript"> if (mouseIsPressed) {
//{!4} First lock the particle, then set the x and y, then unlock() it.
particle1.lock();
particle1.x = mouseX;
particle1.y = mouseY;
particle1.unlock();
}</pre>
<p>And with that, Im ready to put all these elements together in a simple sketch with two particles connected by a spring. One particle is permanently locked in place, and the other can be moved by dragging the mouse. This example is virtually identical to Example 3.11 from Chapter 3.</p>
<div data-type="example">
<h3 id="example-611-simple-spring-with-toxiclibs">Example 6.11: Simple Spring with toxiclibs</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/CSzXIfoWH" data-example-path="examples/06_libraries/6_11_simple_spring_with_toxiclibs"><img src="examples/06_libraries/6_11_simple_spring_with_toxiclibs/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">let { Vec2D, Rect } = toxi.geom;
let { VerletPhysics2D, VerletParticle2D, VerletSpring2D } = toxi.physics2d;
let { GravityBehavior } = toxi.physics2d.behaviors;
let physics;
let particle1, particle2;
function setup() {
createCanvas(640, 240);
// Creating a toxiclibs Verlet physics world
physics = new VerletPhysics2D();
physics.setWorldBounds(new Rect(0, 0, width, height));
physics.addBehavior(new GravityBehavior(new Vec2D(0, 0.5)));
//{!1} What is the rest length of the spring?
let length = 120;
// Creating two Particles
particle1 = new Particle(width / 2, 0, 8);
particle2 = new Particle(width / 2 + length, 0, 8);
// Locking Particle 1 in place
particle1.lock();
// Creating one Spring
let spring = new VerletSpring2D(particle1, particle2, length, 0.01);
//{!3} Must add everything to the world
physics.addParticle(particle1);
physics.addParticle(particle2);
physics.addSpring(spring);
}
function draw() {
//{!1} Must update the physics
physics.update();
background(255);
//{!4} Drawing everything
stroke(0);
line(particle1.x, particle1.y, particle2.x, particle2.y);
particle1.show();
particle2.show();
//{!4} Move particle according to mouse
if (mouseIsPressed) {
particle2.lock();
particle2.x = mouseX;
particle2.y = mouseY;
particle2.unlock();
}
}
// How cute is this simple Particle class?!
class Particle extends VerletParticle2D {
constructor(x, y, r) {
super(x, y);
this.r = r;
}
show() {
fill(127);
stroke(0);
circle(this.x, this.y, this.r * 2);
}
}</pre>
<p>In this example, I'm continuing to visually represent the spring connecting the particles with a line. Keep in mind, however, that the behavior of the spring still exists whether you choose to visually represent it or not. This can open up creative possibilities. For instance, you could decide to make the spring invisible or depict it in a completely different way, perhaps as a series of dots or a shape of your own invention.</p>
<h2 id="soft-body-simulations">Soft Body Simulations</h2>
<p>Verlet physics is particularly well suited for a genre of computer graphics known as soft body simulation. Unlike the <strong>rigid body</strong> simulations of Matter.js, where hard-edged boxes crash into each other and retain their shapes, <strong>soft body</strong> simulations involve objects that can deform and change shape with physics. Soft bodies allow for more flexible, fluid, and organic movements. They can stretch, squish, and jiggle in response to forces and collisions, and they appear . . . well, soft.</p>
<p>One of the first popular examples of soft body physics was <em>SodaConstructor</em>, a game created in the early 2000s. Players could construct and animate custom two-dimensional creatures built out of masses and springs. Other examples over the years have included games like <em>LocoRoco</em>, <em>World of Goo</em>, and more recently, <em>JellyCar</em>.</p>
<p>The basic building blocks of soft body simulations are particles connected by springs—just like the pair particles in the last example. Figure 6.11 shows how to configure a network of particle-spring connections to make various forms.</p>
<figure>
<img src="images/06_libraries/06_libraries_15.png" alt="Figure 6.11: Soft body simulation designs">
<figcaption>Figure 6.11: Soft body simulation designs</figcaption>
</figure>
<p>As the figure shows, a string can be simulated by connecting a line of particles with springs; a blanket can be simulated by connecting a grid of particles with springs; and a cute, cuddly, squishy cartoon character can be simulated with a custom layout of particles connected with springs. Its not much of a leap from one to another.</p>
<h3 id="a-string">A String</h3>
<p>Ill begin by simulating a “soft pendulum”—a bob hanging from a flexible string instead of a rigid arm. As it happens, toxiclibs.js offers a convenient <code>ParticleString2D</code> class that creates a “string” of particles connected by springs in a single constructor call. However, for demonstration purposes, Ill create my own particle string using an array and a <code>for</code> loop. This way youll gain a deeper understanding of the system, enabling you to create your own custom designs beyond a single string in the future.</p>
<p>First, I need an array of particles (Ill use the same <code>Particle</code> class built in the previous example).</p>
<pre class="codesplit" data-code-language="javascript">let particles = [];</pre>
<p>Now, lets say I want to have 20 particles, all spaced 10 pixels apart, as in Figure 6.12.</p>
<figure>
<img src="images/06_libraries/06_libraries_16.png" alt="Figure 6.12: Twenty particles all spaced 10 pixels apart">
<figcaption>Figure 6.12: Twenty particles all spaced 10 pixels apart</figcaption>
</figure>
<p>I can loop from <code>i</code> equals <code>0</code> all the way up to <code>total</code>, creating new particles and setting each ones <code>y</code> position set to <code>i * 10</code>. This way the first particle is at <span data-type="equation">(0,10)</span>, the second at <span data-type="equation">(0,20)</span>, the third at <span data-type="equation">(0,30)</span>, and so on.</p>
<pre class="codesplit" data-code-language="javascript">for (let i = 0; i &#x3C; total; i++) {
//{!1} Spacing them out along the x-axis
let particle = new Particle(i * length, 10, 4);
//{!1} Add the particle to the physics world.
physics.addParticle(particle);
//{!1} Add the particle to the array.
particles.push(particle);
}</pre>
<p>Even though its redundant, Im adding the particles to both the toxiclibs.js <code>physics</code> world and to the <code>particles</code> array. This will help me manage the sketch (especially for the case where there might be more than one string of particles).</p>
<p>Now for the fun part: its time to connect all the particles. Particle index 0 will be connected to particle 1, particle 1 to particle 2, 2 to 3, 3 to 4, and so on (see Figure 6.13).</p>
<figure>
<img src="images/06_libraries/06_libraries_17.png" alt="Figure 6.13: Each particle is connected to the next particle in the array.">
<figcaption>Figure 6.13: Each particle is connected to the next particle in the array.</figcaption>
</figure>
<p>In other words, particle <code>i</code> needs to be connected to particle <code>i+1</code> (except for when <code>i</code> represents the last element of the array).</p>
<pre class="codesplit" data-code-language="javascript">// The loop stops before the last element (total - 1).
for (let i = 0; i &#x3C; total - 1; i++) {
// The spring connects particle i to i+1.
let spring = new VerletSpring2D(particles[i], particles[i + 1], spacing, 0.01);
//{!1} The spring must also be added to the world.
physics.addSpring(spring);
}</pre>
<p>Now, what if I want the string to hang from a fixed point? I can lock one of the particles—perhaps the first, the last, or the middle one. Ill go with the first.</p>
<pre class="codesplit" data-code-language="javascript">particles[0].lock();</pre>
<p>Finally, I need to draw the particles. Instead of drawing them as circles, however, I want to treat them as points in a line. For that, I can use <code>beginShape()</code>, <code>endShape()</code>, and <code>vertex()</code>, accessing the individual particle positions from the array. Ill only use the <code>show()</code> method to draw the last particle as a circle, creating a “bob” at the end of the string.</p>
<div data-type="example">
<h3 id="example-612-soft-swinging-pendulum">Example 6.12: Soft Swinging Pendulum</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/cIygo3QeX" data-example-path="examples/06_libraries/6_12_soft_string"><img src="examples/06_libraries/6_12_soft_string/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">function draw() {
physics.update();
background(255);
stroke(0);
noFill();
beginShape();
for (let particle of particles) {
//{!1} Each particle represents one vertex in the string.
vertex(particle.x, particle.y);
}
endShape();
//{!1} This draws the last particle as a circle.
particles[particles.length - 1].show();
}</pre>
<p>The full code available on the books website also demonstrates how to drag the “bob” particle with the mouse.</p>
<div data-type="exercise">
<h3 id="exercise-610">Exercise 6.10</h3>
<p>Create a hanging cloth simulation using particles and springs. Youll need to connect each particle with its vertical and horizontal neighbors.</p>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/x3FXo0wNZ" data-example-path="examples/06_libraries/exercise_6_13_cloth_simulation"><img src="examples/06_libraries/exercise_6_13_cloth_simulation/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<h3 id="a-soft-body-character">A Soft Body Character</h3>
<p>Now that Ive built a simple connected system—a single string of particles—Ill expand on this idea to create a squishy, cute friend in p5.js, otherwise known as a <strong>soft body character</strong>. The first step is to design a “skeleton” of connected particles. Ill begin with a very simple design with only six vertices, as shown in Figure 6.XX. Each vertex (drawn as a dot) represents a <code>Particle</code> object, and each connection (drawn as a line) represents a <code>Spring</code> object.</p>
<figure>
<img src="images/06_libraries/06_libraries_18.png" alt="Figure 6.X A skeleton for a soft body character. The vertices are numbered according to their positions in an array.">
<figcaption>Figure 6.X A skeleton for a soft body character. The vertices are numbered according to their positions in an array.</figcaption>
</figure>
<p>Creating the particles is the easy part; its exactly the same as before! Id like to make one change, though. Rather than having the <code>setup()</code> function add the particles and springs to the physics world, Ill instead incorporate this responsibility into the <code>Particle</code> constructor itself.</p>
<pre class="codesplit" data-code-language="javascript">class Particle extends VerletParticle2D {
constructor(x, y, r) {
super(x, y);
this.r = r;
//{!1} Adding the object to the global physics world. Inside a class, the object itself is referenced with "this".
physics.addParticle(this);
}
show() {
fill(127);
stroke(0);
circle(this.x, this.y, this.r * 2);
}
}</pre>
<p>While its not strictly necessary, Id also like to make a <code>Spring</code> class that inherits its functionality from <code>VerletSpring2D</code>. For this example, I want the resting length of the spring to always be equal to the distance between the skeletons particles when theyre first created. Additionally, Im keeping things simple here by hardcoding a uniform strength value of <code>0.01</code> in the <code>Spring</code> constructor. You may want to enhance the example with a more sophisticated design where different parts of the soft body character have different degrees of springiness.</p>
<pre class="codesplit" data-code-language="javascript">class Spring extends VerletSpring2D {
// Constructor receives two particles as arguments
constructor(a, b) {
// Calculating the rest length as the distance between the particles
let length = dist(a.x, a.y, b.x, b.y);
// Hardcoding the spring strength
super(a, b, length, 0.01);
//{!1} Another enhancement to to have the object add itself to the physics world!
physics.addSpring(this);
}
}</pre>
<p>Now that I have the <code>Particle</code> and <code>Spring</code> classes, I can assemble the character by adding a series of particles with hardcoded starting positions to a <code>particles</code> array, and a series of spring connections to a <code>springs</code> array.</p>
<pre class="codesplit" data-code-language="javascript">//{!2} Store all the particles and springs in arrays.
let particles = [];
let springs = [];
function setup() {
createCanvas(640, 240);
physics = new VerletPhysics2D();
// Create the vertex positions of the character as particles.
particles.push(new Particle(200, 25));
particles.push(new Particle(400, 25));
particles.push(new Particle(350, 125));
particles.push(new Particle(400, 225));
particles.push(new Particle(200, 225));
particles.push(new Particle(250, 125));
// Connect the vertices with springs.
springs.push(new Spring(particles[0], particles[1]));
springs.push(new Spring(particles[1], particles[2]));
springs.push(new Spring(particles[2], particles[3]));
springs.push(new Spring(particles[3], particles[4]));
springs.push(new Spring(particles[4], particles[5]));
springs.push(new Spring(particles[5], particles[0]));
}</pre>
<p>The beauty of this system is that you can easily expand it to create your own design by adding more particles and springs! However, theres one major issue here: Ive only made connections around the perimeter of the character. if I were to apply a force (like gravity) to the body, it would instantly collapse onto itself. This is where additional “internal” springs come into play, as shown in Figure 6.XX. They keep the characters structure stable while still allowing it to move and squish in a realistic manner.</p>
<figure>
<img src="images/06_libraries/06_libraries_19.png" alt="Figure 6.X: Internal springs keep the structure from collapsing. This is just one possible design. Try others! ">
<figcaption>Figure 6.X: Internal springs keep the structure from collapsing. This is just one possible design. Try others!</figcaption>
</figure>
<p>The final example incorporates the additional springs from Figure 6.X, a gravity force, and mouse interaction.</p>
<div data-type="example">
<h3 id="example-6x-soft-body-character">Example 6.x Soft Body Character</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/-1beeiwUK" data-example-path="examples/06_libraries/soft_body_character_copy"><img src="examples/06_libraries/soft_body_character_copy/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">let physics;
let particles = [];
let springs = [];
function setup() {
createCanvas(640, 240);
physics = new VerletPhysics2D();
let bounds = new Rect(0, 0, width, height);
physics.setWorldBounds(bounds);
physics.addBehavior(new GravityBehavior(new Vec2D(0, 0.5)));
particles.push(new Particle(200, 25));
particles.push(new Particle(400, 25));
particles.push(new Particle(350, 125));
particles.push(new Particle(400, 225));
particles.push(new Particle(200, 225));
particles.push(new Particle(250, 125));
springs.push(new Spring(particles[0], particles[1]));
springs.push(new Spring(particles[1], particles[2]));
springs.push(new Spring(particles[2], particles[3]));
springs.push(new Spring(particles[3], particles[4]));
springs.push(new Spring(particles[4], particles[5]));
springs.push(new Spring(particles[5], particles[0]));
//{!3} Three internal springs!
springs.push(new Spring(particles[5], particles[2]));
springs.push(new Spring(particles[0], particles[3]));
springs.push(new Spring(particles[1], particles[4]));
}
function draw() {
background(255);
physics.update();
//{!7} Drawing the character as one shape
fill(127);
stroke(0);
beginShape();
for (let particle of particles) {
vertex(particle.x, particle.y);
}
endShape(CLOSE);
//{!6} Mouse interaction
if (mouseIsPressed) {
particles[0].lock();
particles[0].x = mouseX;
particles[0].y = mouseY;
particles[0].unlock();
}
}</pre>
<p>For the soft body character example, youll notice that Im no longer drawing all the elements of the physics simulation on the canvas! The <code>show()</code> method of the particles isnt called, and the internal springs that give the character its structure are not rendered with lines. In fact, the springs themselves are never referenced after <code>setup()</code>, since the characters shape is constructed from its particle positions. As such, the springs array isnt strictly needed in this example, although I do fin it useful to have, considering it may be necessary for enhancing the sketch in the future.</p>
<p>Considering the drawing as its own problem, distinct from the character's skeletal structure, also opens up possibilities for adding other design elements such as eyes or antennae. These creative enhancements don't need to be directly connected to the physics of the character, although they can be if you choose to do so!</p>
<div data-type="exercise">
<h3 id="----exercise-611----design-your-own-soft-body-character-with-additional-vertices-and-connections-what-other-design-elements-can-you-add-what-other-forces-and-interactions-can-you-incorporate--">
Exercise 6.11
Design your own soft body character with additional vertices and connections. What other design elements can you add? What other forces and interactions can you incorporate?
</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/hQw1Ih97c" data-example-path="examples/06_libraries/exercise_6_11_soft_body_character_enhanced"><img src="examples/06_libraries/exercise_6_11_soft_body_character_enhanced/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<h3 id="a-force-directed-graph">A Force-Directed Graph</h3>
<p>Have you ever had the following thought? “I have a whole bunch of stuff I want to draw, and I want all that stuff to be spaced out evenly in a nice, neat, organized manner. Otherwise, Ill have trouble sleeping at night.”</p>
<p>This isnt an uncommon problem in computational design. One solution is a <strong>force-directed graph</strong>, a visualization of elements—lets call them “nodes”—in which the positions of those nodes arent manually assigned. Instead, the nodes arrange themselves according to a set of forces. While any forces can be used, a classic method involves spring forces: each node is connected to every other node with a spring, such that when the springs reach equilibrium, the nodes are evenly spaced (see Figure 6.14). Sounds like a job for toxiclibs.js!</p>
<figure>
<img src="images/06_libraries/06_libraries_20.png" alt="Figure 6.14: An example of a “force-directed graph”: clusters of particles connected by spring forces.h">
<figcaption>Figure 6.14: An example of a “force-directed graph”: clusters of particles connected by spring forces.h</figcaption>
</figure>
<p>To create a force-directed graph, Ill first need a class to describe an individual node in the system. Because the term “node” is associated with the JavaScript framework Node.js, Ill stick with the term “particle” to avoid any confusion, and Ill continue using my <code>Particle</code> class from the earlier soft body examples.</p>
<p>Next, Ill encapsulate a list of <span data-type="equation">N</span> particles into a new class called <code>Cluster</code> that represents the graph as a whole. The particles all start out near the center of the canvas.</p>
<pre class="codesplit" data-code-language="javascript">class Cluster {
// A cluster is initialized with N nodes.
constructor(n, length) {
this.particles = [];
for (let i = 0; i &#x3C; n; i++) {
//[offset-down] Heres a funny little detail. The physics will misbehave
// if all the particles are created in exactly the same position.
let x = width / 2 + random(-1, 1);
let y = height / 2 + random(-1, 1);
this.particles.push(new Particle(x, y, 4));
}
}</pre>
<p>Lets assume the <code>Cluster</code> class also has a <code>show()</code> method to draw all the particles in the cluster, and that Ill create a new <code>Cluster</code> object in <code>setup()</code> and render it in <code>draw()</code>. If I ran the sketch as is, nothing would happen. Why? Because I have yet to implement the whole force-directed graph part! I need to connect every single node to every other node with a spring. This is somewhat similar to creating a soft body character, but rather than hand-craft a skeleton, I want to write an algorithm to make all the connections automatically.</p>
<p>What exactly do I mean by that? Say there are four <code>Particle</code> objects: 0, 1, 2 and 3. Here are the connections:</p>
<figure>
<img src="images/06_libraries/06_libraries_21.png" alt="">
<figcaption></figcaption>
</figure>
<table>
<tbody>
<tr>
<td>0</td>
<td>connected to</td>
<td>1</td>
</tr>
<tr>
<td>0</td>
<td>connected to</td>
<td>2</td>
</tr>
<tr>
<td>0</td>
<td>connected to</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>connected to</td>
<td>2</td>
</tr>
<tr>
<td>1</td>
<td>connected to</td>
<td>3</td>
</tr>
<tr>
<td>2</td>
<td>connected to</td>
<td>3</td>
</tr>
</tbody>
</table>
<p>Notice two important details about the list of connections.</p>
<ul>
<li><strong>No particle is connected to itself.</strong> That is, 0 isnt connected to 0, 1 isnt connected to 1, and so on.</li>
<li><strong>Connections arent repeated in reverse.</strong> For example, if 0 is connected to 1, I dont need to explicitly say that 1 is also connected to 0. I already know it is by the definition of how a spring works!</li>
</ul>
<p>How to write the code to make these connections for <span data-type="equation">N</span> particles? Look at the left column of the table of connections. It reads: <span data-type="equation">000 11 2</span>. This tells me that I need to access each particle in the, list from <span data-type="equation">0</span> to <span data-type="equation">N-1</span>.</p>
<pre class="codesplit" data-code-language="javascript"> for (let i = 0; i &#x3C; this.particles.length - 1; i++) {
// Using the variable particle_i to store the particle reference
let particle_i = this.particles[i];</pre>
<p>Now look at the right column of the table. I need to connect node 0 to nodes 1, 2, and 3. For node 1: 2 and 3. For node 2, only 3. In general, for every node <code>i</code>, I need to iterate from <code>i + 1</code> all the way until the end of the array. Ill use the counter variable <code>j</code> for this purpose.</p>
<pre class="codesplit" data-code-language="javascript"> //{!1} Look how j starts at i + 1.
for (let j = i + 1; j &#x3C; this.particles.length; j++) {
let particle_j = this.particles[j];</pre>
<p>For every pair of particles <code>i</code> and <code>j</code>, I can then create a spring. Ill go back to using <code>VerletSpring2D</code> directly, but you could also incorporate a custom <code>Spring</code> class.</p>
<pre class="codesplit" data-code-language="javascript"> //{!1} The spring connects particle i and j.
physics.addSpring(new VerletSpring2D(particle_i, particle_j, length, 0.01));
}
}</pre>
<p>Assuming those connections are made in the <code>Cluster</code> constructor, all thats left is to create the cluster in <code>setup()</code> and call <code>show()</code> in the <code>draw()</code> loop!</p>
<div data-type="example">
<h3 id="example-613-cluster">Example 6.13: Cluster</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/_tbPaFqVX" data-example-path="examples/06_libraries/6_13_force_directed_graph"><img src="examples/06_libraries/6_13_force_directed_graph/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">let { VerletPhysics2D, VerletParticle2D, VerletSpring2D } = toxi.physics2d;
let physics;
let cluster;
function setup() {
createCanvas(640, 240);
physics = new VerletPhysics2D();
//{!1} Create a random cluster
cluster = new Cluster(floor(random(2, 20)), random(10, height / 2));
}
function draw() {
physics.update();
background(255);
//{!1} Draw cluster
cluster.show();
}</pre>
<p>This example illustrates the concept of a force-directed graph, but it does not involve any actual data! Here, the number of nodes in each cluster and the equilibrium length between the nodes are assigned randomly, and the spring strength has a constant value of <code>0.01</code>. In a real-world application, these values could be determined based on your specific data, hopefully resulting in a meaningful visualization of the relationships within the data itself.</p>
<div data-type="exercise">
<h3 id="exercise-611">Exercise 6.11</h3>
<p>Design a cluster-like structure as a skeleton for a cute, cuddly, squishy creature. Add gravity and mouse interaction.</p>
</div>
<div data-type="exercise">
<h3 id="exercise-612">Exercise 6.12</h3>
<p>Expand the force-directed graph to have more than one <code>Cluster</code> object. Use a <code>VerletMinDistanceSpring2D</code> object to connect cluster to cluster. What kind of data might you visualize with this technique?</p>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/WexUSx7dN" data-example-path="examples/06_libraries/exercise_6_12_force_directed_graph"><img src="examples/06_libraries/exercise_6_12_force_directed_graph/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<h2 id="attraction-and-repulsion-behaviors">Attraction and Repulsion Behaviors</h2>
<p>When it came time to create an attraction example for Matter.js, I showed how the <code>Matter.Body</code> class includes an <code>applyForce()</code> method. All I then needed to do was calculate the attraction force <span data-type="equation">F_g = (G \times m_1 \times m_2) \div d^2</span> as a vector and apply it to the body. Similarly, the toxiclibs.js <code>VerletParticle2D</code> class also includes a method called <code>addForce()</code> that can apply any calculated force to a particle.</p>
<p>However, toxiclibs.js also takes this idea one step further by offering built-in functionality for common forces (called “behaviors”) such as attraction! For example, if you add an<code>AttractionBehavior</code> object to a particular <code>VerletParticle2D</code> object, all other particles in the physics world will experience an attraction force toward that particle.</p>
<p>Say I create an instance of my <code>Particle</code> class (which extends the <code>VerletParticle2D</code> class).</p>
<pre class="codesplit" data-code-language="javascript">let particle = new Particle(320, 120);</pre>
<p>Now I can create an <code>AttractionBehavior</code> associated with that particle.</p>
<pre class="codesplit" data-code-language="javascript">let distance = 20;
let strength = 0.1;
let behavior = new AttractionBehavior(particle, distance, strength);</pre>
<p>Notice how the behavior is created with three arguments: a particle to assign it to, a distance, and a strength. The distance specifies the range within which the behavior will be applied. In this case, only particles within 20 pixels will experience the attraction force. The strength, of course, specifies how strong the force is.</p>
<p>Finally, in order for the force to be activated, the behavior needs to be added to the physics world.</p>
<pre class="codesplit" data-code-language="javascript">physics.addBehavior(behavior);</pre>
<p>Now everything that lives in the physics simulation will always be attracted to that particle, as long as its within the distance threshold.</p>
<p>The <code>AttractionBehavior</code> class is a very powerful tool. For example, even though toxiclibs.js doesnt automatically handle collisions like Matter.js does, you can create a collision-like simulation by adding an <code>AttractionBehavior</code> with a negative strength—a repulsive behavior—to each and every particle. If the force is strong and only activated within a short range (scaled to the particles radius), the result is much like a rigid body collision. Heres how to modify the <code>Particle</code> class to do this.</p>
<pre class="codesplit" data-code-language="javascript">class Particle extends VerletParticle2D {
constructor(x, y, r) {
super(x, y);
this.r = r;
//[offset-down] Every time a Particle is made, an AttractionBehavior is
// generated and added to the physics world.
// Note that when the strength
// is negative, its a repulsive force!
physics.addBehavior(new AttractionBehavior(this, r * 4, -1));
}
show() {
fill(127);
stroke(0);
circle(this.x, this.y, this.r * 2);
}
}</pre>
<p>I can now remake the attraction example from Chapter 2 with a single <code>Attractor</code> 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 <code>width</code> to account for any movement of the attractor, and for particles located outside the canvas boundaries.</p>
<div data-type="example">
<h3 id="example-614-attraction-and-repulsion-behaviors">Example 6.14: Attraction (and Repulsion) Behaviors</h3>
<figure>
<div data-type="embed" data-p5-editor="https://editor.p5js.org/natureofcode/sketches/tjIs8XaXP" data-example-path="examples/06_libraries/6_14_attraction_behaviors"><img src="examples/06_libraries/6_14_attraction_behaviors/screenshot.png"></div>
<figcaption></figcaption>
</figure>
</div>
<pre class="codesplit" data-code-language="javascript">class Attractor extends VerletParticle2D {
constructor(x, y, r) {
super(x, y);
this.r = r;
// Attracts all particles always
physics.addBehavior(new AttractionBehavior(this, width, 0.1));
// Repels particles that come within its radius
physics.addBehavior(new AttractionBehavior(this, this.r, -10));
// This is a nice improvement where the attractor adds itself to the physics
physics.addParticle(this);
}
show() {
fill(0);
circle(this.x, this.y, this.r * 2);
}
}</pre>
<p>Just as discussed in Chapter 5s section on spatial subdivision and “binning”, toxiclibs.js projects with large numbers of particles interacting with each other can run very slow due to the <span data-type="equation">N^2</span> nature of the algorithm (every particle checking every other particle). To speed up the simulation, you could potentially use the manual <code>addForce()</code>method in conjunction with a binning algorithm. Keep in mind, this would also require you to manually calculate the attraction force, as the built-in <code>AttractionBehavior</code> would no longer apply.</p>
<div data-type="exercise">
<h3 id="exercise-613">Exercise 6.13</h3>
<p>Use <code>AttractionBehavior</code> in conjunction with spring forces.</p>
</div>
<div data-type="project">
<h3 id="the-ecosystem-project-5">The Ecosystem Project</h3>
<p>Step 6 Exercise:</p>
<p>Take your system of creatures from Step 5 and use a physics engine to drive their motion and behaviors. Some possibilities:</p>
<ul>
<li>Use Matter.js to allow collisions between creatures. Consider triggering an event when two creatures collide.</li>
<li>Use Matter.js to augment the design of your creatures. Build a skeleton with distance joints or make appendages with revolute joints.</li>
<li>Use toxiclibs.js to augment the design of your creature. Use a chain of toxiclibs particles for tentacles or a mesh of springs as a skeleton.</li>
<li>Use toxiclibs.js to add attraction and repulsion behaviors to your creatures.</li>
<li>Use spring (or joint) connections between objects to control their interactions. Create and delete these springs on the fly. Consider making these connections visible or invisible to the viewer.</li>
</ul>
</div>
</section>