-
-
Notifications
You must be signed in to change notification settings - Fork 53
/
06_libraries.html
1758 lines (1719 loc) · 148 KB
/
06_libraries.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<section data-type="chapter" id="section-physics-libraries">
<h1 id="chapter-6-physics-libraries">Chapter 6. Physics Libraries</h1>
<div class="chapter-opening-quote">
<blockquote data-type="epigraph">
<p>A library implies an act of faith</p>
<p>Which generations still in darkness hid</p>
<p>Sign in their night, in witness of the dawn.</p>
<div class="chapter-opening-quote-source">
<p>—Victor Hugo</p>
</div>
</blockquote>
</div>
<div class="chapter-opening-figure">
<figure>
<img src="images/06_libraries/06_libraries_1.png" alt="">
<figcaption></figcaption>
</figure>
<h3 id="living-root-bridges-photo-by-arshiya-urveeja-bose">Living root bridges (photo by Arshiya Urveeja Bose)</h3>
<p>In the Indian state of Meghalaya, the Khasi and Jaiñtia peoples live in areas that experience some of the highest rainfall in the world. During the monsoon season, floods often make traveling between villages impossible. As a result, the ancient tradition of constructing living root bridges emerged. These bridges, like the double living root bridge in East Khasi shown here, are created by guiding and growing tree roots through bamboo, palm trunks, or steel scaffolding. They grow and become stronger as the roots interact with the environment, forming adaptive, springlike connections.</p>
</div>
<p></p>
<p>Think about what you’ve accomplished so far in this book. You’ve done the following:</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 aren’t the first or only people to do this. The world of computer graphics and programming is full of prewritten code libraries dedicated to physics simulations.</p>
<p>Just try searching <em>open source physics engine</em> and you could spend the rest of your day poring over a host of rich and complex codebases. This begs the question: If an existing code library takes care of physics simulation, why should you bother learning how to write any of the algorithms yourself? Here’s where the philosophy behind this book comes into play. While many libraries provide out-of-the-box physics to experiment with (super-awesome, sophisticated, and robust physics at that), there are several good reasons for learning the fundamentals from scratch before diving into such libraries.</p>
<p>First, without an understanding of vectors, forces, and trigonometry, it’s easy to get lost just reading the documentation of a library, let alone using it. Second, even though a library may take care of the math behind the scenes, it won’t necessarily simplify your code. A great deal of overhead may be required in understanding how a library works and what it expects from you code-wise. Finally, as wonderful as a physics engine might be, if you look deep down into your heart, you’ll likely see that you seek to create worlds and visualizations that stretch the limits of the imagination. A library may be great, but it provides only a limited set of features. It’s important to know when to live within those limitations in the pursuit of a creative coding project and when those limits will prove to be confining.</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 don’t mean to imply that these are the only libraries you should use for any and all creative coding projects that could benefit from a physics engine (see <a href="#other-physics-libraries" class="page-reference">“Other Physics Libraries”</a> for alternatives, and check the book’s website for ports of the chapter’s examples to other libraries). However, both libraries integrate nicely with p5.js and will allow me to demonstrate the fundamental concepts behind physics engines and how they relate to and build upon the material I’ve covered so far.</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>I’ve made the case for writing your own physics simulations (as you’ve learned to do in the previous chapters), but why use a physics library? After all, adding any external framework or library to a project introduces complexity and extra code. Is that additional overhead worth it? If you just want to simulate a circle falling down because of gravity, for example, do you really need to import an entire physics engine and learn its API? As the early chapters of this book hopefully demonstrated, probably not. Lots of scenarios like this are simple enough for you to get by writing the code yourself.</p>
<p>But consider another scenario. What if you want to have 100 circles falling? And what if they aren’t circles at all, but rather irregularly shaped polygons? And what if you want these polygons to bounce off one another in a realistic manner when they collide?</p>
<p>You may have noticed that while I’ve covered motion and forces in detail, I’ve so far skipped over a rather important aspect of physics simulation: <strong>collisions</strong>. Let’s pretend for a moment that you aren’t reading a chapter about physics libraries and that I’ve decided right now to explain how to handle collisions in a particle system. I’d have to cover two distinct algorithms that address these 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 you’re working with simple geometric shapes, question 1 isn’t too tough. In fact, perhaps you’ve encountered it before. With two circles, for instance, you know they’re 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_2.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>That’s easy enough, but how about calculating the circles’ velocities after the collision? This is where I’m going to stop the discussion. Why, you ask? It’s not that understanding the math behind collisions isn’t important or valuable. (In fact, I’m including additional examples on the website related to collisions without a physics library.) The reason for stopping is that life is short! (Let this also be a reason for you to consider going outside and frolicking for a bit before sitting down to write your next sketch.) You can’t expect to master every detail of physics simulation. And while you might enjoy learning about collision resolution for circles, it’s only going to make you want to work with rectangles next. And then with strangely shaped polygons. And then curved surfaces. And then swinging pendulums colliding with springy springs. And then, and then, and then . . .</p>
<p>Incorporating complex features like collisions into a p5.js sketch while still having time to spend with friends and family—that’s the reason for this chapter. People have spent years developing solutions to these kinds of problems, and beautiful JavaScript libraries like Matter.js and Toxiclibs.js are the fruits of those efforts. You don’t need to reinvent the proverbial wheel, at least for now.</p>
<p>In conclusion, if you find yourself describing an idea for a p5.js sketch and the word <em>collisions</em> comes up, then it’s likely time to learn to use a physics engine.</p>
<div class="allow-break">
<div data-type="note">
<h3 id="other-physics-libraries">Other Physics Libraries</h3>
<p>A multitude of other physics libraries are worth exploring alongside this chapter’s two case studies, each with unique strengths that may offer advantages in certain kinds of projects. In fact, when I first began writing this book, Matter.js didn’t exist, so the physics engine I initially used to demonstrate the examples was Box2D. It was (and likely still is) the most well-known physics engine of them all.</p>
<p><a href="https://box2d.org/">Box2D</a> began as a set of physics tutorials written in C++ by Erin Catto for the Game Developers Conference in 2006. Since then, Box2D has evolved into a rich and elaborate open source physics engine. It’s been used for countless projects, most notably highly successful games such as the award-winning <em>Crayon Physics</em> and the runaway hit <em>Angry Birds</em>.</p>
<p>One important feature of Box2D is that it’s a true physics engine: it knows nothing about computer graphics and the world of pixels, and instead does all its measurements and calculations in real-world units like meters, kilograms, and seconds. It’s just that its “world” (a key term in Box2D) is a 2D plane with top, bottom, left, and right edges. You tell it things like “The gravity of the world is 9.81 newtons per kilogram, and a circle with a radius of 4 meters and a mass of 50 kilograms is located 10 meters above the world’s bottom.” Box2D will then tell you things like “One second later, the rectangle is at 5 meters from the bottom; two seconds later, it’s 10 meters below,” and so on.</p>
<p>While this provides for an amazingly accurate and robust physics engine (one that’s highly optimized and fast for C++ projects), it also necessitates lots of complicated code to translate back and forth between Box2D’s physics world and the world you want to draw—the pixel world of the graphics canvas. This creates a tremendous burden for the coder. I will, as best I can, continue to maintain a set of Box2D-compatible examples for this book (there are several JavaScript ports), but I believe the relative simplicity of working with a library like Matter.js that is native to JavaScript and uses pixels as the unit of measurement will make for a more intuitive and friendly bridge from my p5.js examples.</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>
</div>
<h2 id="importing-the-matterjs-library">Importing the Matter.js Library</h2>
<p>In a moment, I’ll turn to working with Matter.js, created by Liam Brummitt in 2014. But before you can use an external JavaScript library in a p5.js project, you need to import it into your sketch. As you’re already quite aware, I’m using the official p5.js web editor for developing and sharing this book’s code examples. The easiest way to add a library is to edit the <em>index.html</em> file that’s part of every new p5.js sketch created in the editor.</p>
<p>To do that, first expand the file navigation bar on the left-hand side of the editor and select <em>index.html</em>, as shown in Figure 6.2.</p>
<p>The file includes a series of <code><script></code> tags inside the HTML tags <code><head></code> and <code></head></code>. This is how JavaScript libraries are referenced in a p5.js sketch. It’s no different from including <code>sketch.js</code> or <code>particle.js</code> in the page’s <code><body></code>, only here, instead of keeping and editing a copy of the JavaScript code, 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 accessed by millions upon millions of users, CDNs need to be pretty good at their job of serving up these libraries.</p>
<figure>
<img src="images/06_libraries/06_libraries_3.png" alt="Figure 6.2: Accessing a sketch’s index.html file">
<figcaption>Figure 6.2: Accessing a sketch’s <em>index.html</em> file</figcaption>
</figure>
<p>You should already see a <code><script></code> tag referencing the CDN for p5.js (it may be a later version by the time you are reading this):</p>
<pre class="codesplit" data-code-language="html"><script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.js"></script></pre>
<p>To use Matter.js, add another <code><script></code> tag referencing its CDN right below the one for p5:</p>
<pre class="codesplit" data-code-language="html"><script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script></pre>
<p>At the time of this writing, the most recent version of Matter.js is <code>0.19.0</code>, and that’s what I’ve referenced in this snippet. As Matter.js updates and new versions are released, it’s often a good idea to upgrade, but by referencing a specific version that you know works with your sketch, you don’t 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. Here’s a pseudocode generalization of all the examples in <a href="/vectors#section-vectors">Chapters 1</a> through <a href="/autonomous-agents#section-autonomous-agents">5</a>:</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 (<span data-type="equation">F = M \times A</span>).</li>
<li>Update the positions of all the objects based on their acceleration.</li>
<li>Draw all the objects.</li>
</ol>
<p>By contrast, here’s the pseudocode for a Matter.js example:</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. I’ve eliminated all 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 reflection of the overall process. In this sense, Matter.js is a bit like a magic box. In <code>setup()</code>, I’m going to say to Matter, “Hello there. Here are all of the things I want in my world.” Then, in <code>draw()</code>, I’m going to politely ask Matter, “Oh, hello again. If it’s not too much trouble, I’d like to draw all of those things in my world. Could you please tell me where they are?”</p>
<p>The bad news: the process is not quite as simple as the pseudocode might lead you to believe. Actually making the stuff that goes into the Matter.js world requires several steps related to building and configuring different kinds of shapes.</p>
<div class="avoid-break">
<p>It’s 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>
<ul>
<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 indicating how the world is updated over time.</li>
</ul>
</div>
<ul>
<li><strong>Bodies:</strong> The primary elements in the world, corresponding to the physical objects being simulated. A body has a position and a velocity. Sound familiar? It’s basically another version of the class I’ve been building throughout <a href="/vectors#section-vectors">Chapters 1</a> through <a href="/autonomous-agents#section-autonomous-agents">5</a>. It also has geometry to define its shape. It’s important to note that <em>body</em> is a generic term that physics engines use to describe a <em>thing</em> in the world (similarly to the term <em>particle</em>); it isn’t 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 of a composite, and every body created has to be added to the world.</li>
<li><strong>Constraints:</strong> Act as connections between bodies.</li>
</ul>
<p>In the coming sections, I’ll walk through each of these elements in detail, building several examples along the way. But first, there’s one other important element to briefly discuss:</p>
<ul>
<li><strong>Vector:</strong> Describes an entity with magnitude and direction using x- and y-components, defining positions, velocities, and forces in a Matter.js world.</li>
</ul>
<p>This brings us to an important crossroads. Any physics library is fundamentally built around vectors, and depending on how you spin it, that’s either a good thing or a bad thing. The good part is that you’ve just spent several chapters familiarizing yourself with what it means to describe motion and forces with vectors, so there’s 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 don’t get to use <code>p5.Vector</code> anymore.</p>
<p>It’s been great that p5.js has a built-in vector representation, but anytime you use a physics library, you’ll likely discover that it includes its own separate vector implementation, designed to be especially compatible with the rest of the library’s 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 won’t have to learn any new concepts, you do have to get used to new naming conventions and syntax. To illustrate, I’ll 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><code>let v = createVector(1, -1);</code></pre>
</td>
<td>
<pre><code>let v = Matter.Vector.create(1, -1);</code></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><code>let a = createVector(1, -1);
let b = createVector(3, 4);
a.add(b);</code></pre>
</td>
<td>
<pre><code>let a = Matter.Vector.create(1, -1);
let b = Matter.Vector.create(3, 4);
Matter.Vector.add(a, b, a);</code></pre>
</td>
</tr>
</tbody>
</table>
<p>That overwrites vector <code>a</code> with the result. Here’s 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><code>let a = createVector(1, -1);
let b = createVector(3, 4);
let c = p5.Vector.add(a, b);</code></pre>
</td>
<td>
<pre><code>let a = Matter.Vector.create(1, -1);
let b = Matter.Vector.create(3, 4);
let c = Matter.Vector.add(a, b);</code></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><code>let v = createVector(1, -1);
v.mult(4);</code></pre>
</td>
<td>
<pre><code>let v = Matter.Vector.create(1, -1);
v = Matter.Vector.mult(v, 4);</code></pre>
</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><code>let v = createVector(3, 4);
let m = v.mag();
v.normalize();</code></pre>
</td>
<td>
<pre><code>let v = Matter.Vector.create(3, 4);
let m = Matter.Vector.magnitude(v);
v = Matter.Vector.normalise(v);</code></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 unusual 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.js, you can’t use <code>circle</code> as a variable name. Namespacing a library protects against these kinds of errors and naming conflicts, and it’s why you’ll see everything in Matter.js called with the <code>Matter</code> prefix.</p>
<p>In addition, unlike p5.js’s static and nonstatic versions of vector methods like <code>add()</code> and <code>mult()</code>, all vector methods in Matter.js 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>I’ll cover more of the basics for working with <code>Matter.Vector</code> in this chapter, but for details, you can find the <a href="https://brm.io/matter-js">full documentation on the Matter.js website</a>.</p>
<h3 id="engine">Engine</h3>
<p>Many physics libraries include a <em>world</em> 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 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 <code>Engine</code> class
let Engine = Matter.Engine;
//{!1} A reference to the Matter.js physics engine
let engine;
function setup() {
createCanvas(640, 360);
// Create the Matter.js engine.
engine = Engine.create();
}</pre>
<p>Notice that the very first line of code creates an <code>Engine</code> variable and sets it equal to <code>Matter.Engine</code>. Here, I’m 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 won’t be using the word <code>Engine</code> for any other variables, nor does it conflict with something in p5.js. I’ll 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 won’t always show them in the book text.)</p>
<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 (0, 1) pointing down. You can change this default by accessing the <code>gravity</code> variable:</p>
<pre class="codesplit" data-code-language="javascript"> // Change the engine’s gravity to point horizontally.
engine.gravity.x = 1;
engine.gravity.y = 0;</pre>
<p>Of course, gravity doesn’t 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 (0, 0) vector.</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">const { Engine } = Matter;</pre>
<p>Hold on. Did you catch that I snuck in a <code>const</code> here? I know I said back in <a href="/random#section-random">Chapter 0</a> that I would use only <code>let</code> for variable declarations throughout this book. However, working with an external library is a really good time to dip your toe in the <code>const</code> waters. In JavaScript, <code>const</code> is used for declaring variables whose values should never be reassigned after initialization. In this case, I want to protect myself from accidentally overwriting the <code>Engine</code> variable later in the code, which would likely break everything!</p>
<p>With that out of the way, let’s look at how the destructuring syntax really shines when you need to create aliases to multiple properties of the same object:</p>
<pre class="codesplit" data-code-language="javascript">// Use object destructuring to extract aliases for <code>Engine</code> and <code>Vector</code>.
const { 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. I’ll use this technique throughout the chapter’s examples.</p>
</div>
<p>Once the world is initialized, it’s time to 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. It’s the equivalent of 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 (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 you’re probably more familiar with calling a constructor to create an object—for example, with <code>new Particle()</code>—you’ve 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 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>. I’ll 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.js’s <code>rect()</code> function. In this case, however, the method isn’t <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> works only 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 their motion, however. For example, density ultimately determines that body’s 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 <strong>object literal</strong>, a collection of key-value pairs separated by commas and enclosed in curly brackets:</p>
<pre class="codesplit" data-code-language="javascript">//{!5} Specify the properties of this body in an object literal.
let options = {
friction: 0.5,
restitution: 0.8,
density: 0.002
};
let box = Matter.Bodies.rectangle(x, y, w, h, options);</pre>
<p>Each key in the object literal (for example, <code>friction</code>) serves as a unique identifier, and its value (<code>0.5</code>) is the data associated with that key. You can think of an object literal as a simple dictionary or lookup table—in this case, holding the desired settings for a new Matter.js body. Note, however, that while the <code>options</code> argument 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">// Set an 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 isn’t 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 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—it’s a mistake I’ve made on countless occasions. If you’re ever wondering why one of your objects doesn’t appear or move along with the world’s physics, always check that you’ve 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 following code 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 to the world, Matter.js will always know it’s there, check it for collisions, and update its position appropriately, according to any forces in the environment. It’ll do all that without you having to lift a finger! But how do you draw the body?</p>
<p>In the next section, I’ll show you how to query Matter.js for the position of the various bodies in order to render the world with p5.js. The way 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 you’ve designed. It provides ways to customize the <em>debug drawing</em> style, but I find the defaults perfectly adequate for quickly double-checking that I’ve 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 I’ll call <code>params</code>.</p>
<div class="avoid-break">
<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>
</div>
<p>Notice that I’m 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 in a specific canvas. Matter.js doesn’t know about p5.js, so the canvas it’s 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×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>One more critical order of business remains: physics engines must be told to step forward in time. Since I’m using the built-in renderer, I can also use the built-in runner, which runs the engine at a default frame rate of 60 frames per second. The runner is also customizable, but the details aren’t terribly important since the goal here is to move toward using p5.js’s <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>Here’s 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 the ground body to ensure that it remains in a fixed position. I’ll cover more details about static bodies in <a href="#static-matterjs-bodies" class="page-reference">“Static Matter.js Bodies”</a>.</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 the Matter.js classes needed for this sketch.
const { Engine, Bodies, Composite, Body, Vector, Render } = 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 it to the p5.js canvas.
let render = Matter.Render.create({
canvas: canvas.elt, engine,
options: { width: width, height: height },
});
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 the initial velocity of the box.
Body.setVelocity(box, Vector.create(5, 0));
Body.setAngularVelocity(box, 0.1);
// Add the 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 the runner.
let runner = Matter.Runner.create();
// Run the engine.
Matter.Runner.run(runner, engine);
}</pre>
<p>There’s no <code>draw()</code> function here, and all the variables are local to <code>setup()</code>. In fact, I’m not using any p5.js capabilities (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 you’ve just seen, it can handle<br>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 I’d 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.js.</p>
<p>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, you’ll be able to code as you’re 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.3.</p>
<figure>
<img src="images/06_libraries/06_libraries_4.png" alt="Figure 6.3: The file structure of a typical p5.js sketch">
<figcaption>Figure 6.3: The file structure of a typical p5.js sketch</figcaption>
</figure>
<p>Structurally, this looks like just another p5.js sketch. There’s a main <em>sketch.js</em> file, as well as <em>box.js</em>. This sort of extra file is where I’d 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 <code>(x, y)</code> position and a width.
this.x = x;
this.y = y;
this.w = 16;
}
show() {
//{!5} The box is drawn as a <code>square()</code>.
rectMode(CENTER);
fill(127);
stroke(0);
strokeWeight(2);
square(this.x, this.y, this.w);
}
}</pre>
<p>Now I’ll write a <em>sketch.js</em> file that creates a new <code>Box</code> whenever the mouse is clicked and stores all the <code>Box</code> objects in an array. (This is the same approach I took in the particle system examples from <a href="/particles#section-particles">Chapter 4</a>.)</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 <code>Box</code> objects
let boxes = [];
function setup() {
createCanvas(640, 360);
}
function draw() {
background(255);
//{!4} When the mouse is clicked, add a new <code>Box</code> object.
if (mouseIsPressed) {
let box = new Box(mouseX, mouseY);
boxes.push(box);
}
//{!3} Display all the <code>Box</code> objects.
for (let box of boxes) {
box.show();
}
}</pre>
<p>Right now, this sketch draws fixed boxes to the screen. Here’s 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>I’ll 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 isn’t too tough: I’ve already demonstrated all the elements needed to build a Matter.js world. (And don’t 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.js classes and create an <code>Engine</code> object in <code>setup()</code>:</p>
<pre class="codesplit" data-code-language="javascript">//{!3} Aliases for <code>Engine</code>, <code>Bodies</code>, and <code>Composite</code>
let { Engine, Bodies, Composite } = Matter;
//{!1} The engine is now a global variable!
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 the 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 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 documentation</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>I’ve 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 object’s position to Matter.js. I no longer need to keep track of anything related to position, velocity, or acceleration. Instead, I need to keep track of only the existence of a Matter.js body and have faith that the physics engine will do the rest.”</p>
<div class="snip-below">
<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>
</div>
<p>I don’t need <code>this.x</code> and <code>this.y</code> position variables anymore. The <code>Box</code> constructor takes in the starting x- and y-coordinates, passes them along to <code>Bodies.rectangle()</code> to create a new Matter.js body, and then forgets about them. As you’ll 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, it’s 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-body">Step 3: Draw the Body</h3>
<p>Almost there. Before I introduced Matter.js into the sketch, drawing <code>Box</code> was easy. The object’s position was stored in the variables <code>this.x</code> and <code>this.y</code>:</p>
<pre class="codesplit" data-code-language="javascript"> // Draw the object by using <code>square()</code>.
show() {
rectMode(CENTER);
fill(127);
stroke(0);
strokeWeight(2);
square(this.x, this.y, this.w);
}</pre>
<p>Now that Matter.js manages the object’s 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 isn’t 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 by 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 body’s 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>It’s important to note here that if you delete a <code>Box</code> object from the <code>boxes</code> array—perhaps when it moves outside the boundaries of the canvas or reaches the end of its life span, as demonstrated in <a href="/particles#section-particles">Chapter 4</a>—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, and 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>
<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 in this image. Feel free to be creative in the way you draw the boxes!</p>
<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></figcaption>
</figure>
</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 downward because of 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">// Create a fixed (static) boundary body.
let options = { isStatic: true };
let boundary = Bodies.rectangle(x, y, w, h, options);</pre>
<p>I’m 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. I’ll 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, I’ll 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 the body in place by setting <code>isStatic</code> to <code>true</code>!
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 the boundary can never move, <code>show()</code> 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 don’t 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 I’ve demonstrated how easy it is to use a primitive shape like a rectangle or circle with Matter.js, let’s imagine that you want to create a more interesting body, such as the abstract character in Figure 6.4.</p>
<figure>
<img src="images/06_libraries/06_libraries_5.png" alt="Figure 6.4: A compound body made up of multiple shapes">
<figcaption>Figure 6.4: A compound body made up of multiple shapes</figcaption>
</figure>
<p>Two strategies can be used to make such complex forms. The generic <code>Bodies.polygon()</code> method can create any regular polygon (pentagon, hexagon, and so on). Additionally, <code>Bodies.trapezoid()</code> makes a quadrilateral with at least one pair of parallel sides:</p>
<pre class="codesplit" data-code-language="javascript">// A regular hexagon (six-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. I’ll 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>
<div class="snip-below">
<pre class="codesplit" data-code-language="javascript">class CustomShape {
constructor(x, y) {
//{!6} An array of five 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} Make a body 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>
</div>
<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.5 shows the five vertices used to create the bodies in Example 6.4. Notice that 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_6.png" alt="Figure 6.5: Vertices on a custom polygon oriented in clockwise order">
<figcaption>Figure 6.5: 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.6, a <strong>concave</strong> shape has a surface that curves inward, whereas <strong>convex</strong> is the opposite. Every internal angle in a convex shape must be 180 degrees or less. Matter.js can 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_7.png" alt="Figure 6.6: A concave shape can be drawn with multiple convex shapes. ">
<figcaption>Figure 6.6: 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 p5.js’s <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 (0, 0), for drawing purposes. However, it’s best to query Matter.js for the positions instead. This way, there’s no need to use <code>translate()</code> or <code>rotate()</code>, since the Matter.js body stores its vertices as absolute world positions:</p>
<div class="snip-above">
<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>
</div>
<p>The Matter.js body stores the array of its vertex positions inside a <code>vertices</code> property. Notice that I can then use a <code>for...of</code> loop to cycle through the vertices 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 here.</p>
<figure>
<img src="images/06_libraries/06_libraries_8.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>compound body</strong> made up of multiple shapes! How about creating a delicious lollipop with a thin rectangle and a circle on top?</p>
<p>I’ll 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">// Make the bodies.
let part1 = Bodies.rectangle(x, y, w, h);
let part2 = Bodies.circle(x, y, r);
// Join the two bodies together in an array.
let body = Body.create({ parts: [part1, part2] });
// Add 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 isn’t quite right. If you run it, you’ll see that both shapes are centered on the same (<em>x</em>, <em>y</em>) position, as in Figure 6.7.</p>
<figure>
<img src="images/06_libraries/06_libraries_9.png" alt="Figure 6.7: A rectangle and a circle with the same (x, y) reference point">
<figcaption>Figure 6.7: A rectangle and a circle with the same (<em>x</em>, <em>y</em>) 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.8.</p>
<figure>
<img src="images/06_libraries/06_libraries_10.png" alt="Figure 6.8: A circle placed relative to a rectangle with a horizontal offset">
<figcaption>Figure 6.8: A circle placed relative to a rectangle with a horizontal offset</figcaption>
</figure>
<p>I’ll use half the width of the rectangle as the offset, so the circle is centered on the edge of the rectangle:</p>
<pre class="codesplit" data-code-language="javascript">
let part1 = Bodies.rectangle(x, y, w, h);
//{!2} Add 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 the lollipop’s body has two parts, drawing it is a bit trickier. I could take multiple approaches. For example, I could use the body’s <code>vertices</code> array and draw the lollipop as a custom shape, much like Example 6.4. (Every body stores an array of vertices, even if it wasn’t created with the <code>fromVertices()</code> method.) Since each part of the lollipop is a primitive shape, however, I’d prefer to separately translate to each part’s position and rotate by the collective body’s 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);
// Translate and rotate the rectangle (<code>part1</code>).
push();
translate(position1.x, position1.y);
rotate(angle);
rectMode(CENTER);
rect(0, 0, this.w, this.h);
pop();
// Translate and rotate the circle (<code>part2</code>).
push();
translate(position2.x, position2.y);
rotate(angle);
circle(0, 0, this.r * 2);
pop();
}</pre>
<p>Before moving on, I want to stress that what you draw in your canvas window doesn’t magically experience perfect physics just by the mere act of creating Matter.js bodies. The chapter’s examples have worked because I’ve been carefully matching the way I’ve drawn each p5.js body with the way I’ve defined the geometry of each Matter.js body. If you accidentally draw a shape differently, you won’t get an error—not from p5.js or from Matter.js. However, your sketch will look odd, and the physics won’t work correctly because the world you’re seeing won’t 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>). I’ve 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 circle’s position manually using an offset. After all, that’s how I conceived of the compound shape to begin with (look back at Figure 6.8):</p>
<pre class="codesplit" data-code-language="javascript"> show() {
//{!1} Getting the body position rather than the parts
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.9 shows the result of this change.</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.9: What happens when the shapes are drawn differently from their Matter.js configurations</figcaption>
</figure>
<p>At first glance, this new version may look fine, but if you look closer, the collisions are off and<br>the shapes overlap in odd ways. This isn’t because the physics is broken; it’s because I’m not communicating properly between p5.js and Matter.js. It turns out the overall body position isn’t 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 I’m drawing each body in the wrong place! (In the online version, you can toggle the correct and incorrect renderings by clicking the mouse.)</p>
<div data-type="exercise">
<h3 id="exercise-64">Exercise 6.4</h3>
<p>Make your own little alien being by using multiple shapes attached to a single body. Remember, you aren’t 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="matterjs-constraints">Matter.js Constraints</h2>
<p>A Matter.js <strong>constraint</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. Constraints have three types: 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"><strong>Distance Constraints</strong></h3>
<div class="half-width-right">
<figure>
<img src="images/06_libraries/06_libraries_11.png" alt="Figure 6.10: A constraint is a connection between two bodies at an anchor point for each body.">
<figcaption>Figure 6.10: A constraint is a connection between two bodies at an anchor point for each body.</figcaption>
</figure>
</div>
<p>A <strong>distance constraint</strong> is a connection of fixed length between two bodies, similar to a spring force connecting two shapes in <a href="/oscillation#section-oscillation">Chapter 3</a>. The constraint is attached to each body at a specified <strong>anchor</strong>, a point relative to the body’s center (see Figure 6.10). Depending on the constraint’s stiffness property, the “fixed” length can exhibit variability, much as a spring can be more or less rigid.</p>
<p>Defining a constraint uses a similar methodology as creating bodies, only you need to have two bodies ready to go. Let’s assume that two <code>Particle</code> objects each store a reference to a Matter.js body in a property called <code>body</code>. I’ll 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 constraint’s 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 from 0 to 1 that represents the rigidity of the constraint, with 1 being fully rigid and 0 being completely soft.</li>
</ul>
<p>These settings get packaged up in an object literal:</p>
<div class="avoid-break">
<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>
</div>
<p>Technically, the only required options are <code>bodyA</code> and <code>bodyB</code>, the two bodies connected by the constraint. If you don’t 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 body’s 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 didn’t include are <code>damping</code> and <code>angularStiffness</code>. The <code>damping</code> option affects the constraint’s resistance to motion, with higher values causing the constraint to lose energy more quickly. The <code>angularStiffness</code> option controls the rigidity of the constraint’s 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 relationships among multiple bodies. Here’s an example of a class that represents a swinging pendulum (mirroring Example 3.11 from <a href="/oscillation#section-oscillation">Chapter 3</a>).</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 the 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);
//{!2} 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 in the following image. 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 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>
<div class="half-width-right">
<figure>
<img src="images/06_libraries/06_libraries_12.png" alt="Figure 6.11: A revolute constraint is a connection between two bodies at a single anchor point, or hinge.">
<figcaption>Figure 6.11: A revolute constraint is a connection between two bodies at a single anchor point, or hinge.</figcaption>
</figure>
</div>
<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.11). While Matter.js doesn’t have a separate revolute constraint, you can make one with a regular <code>Constraint</code> of length 0. 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, I’d like to create a spinning rectangle (akin to a propeller or windmill) in a fixed position. For this case, I need only one body connected to a point. This simplifies the code since I don’t 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 position with 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 (<code>x</code>, <code>y</code>) position with a length of 0 and stiffness of 1.
let options = {
bodyA: this.body,
pointB: { x: x, y: 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 the code together, I’ll 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: x, y: 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 isn’t 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 don’t need those elements to participate in the simulation itself.</p>
<div data-type="exercise">
<h3 id="exercise-66">Exercise 6.6</h3>
<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 body’s position, and you have access to the mouse’s position. What’s 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 code will move the body, it will also have the unfortunate result of breaking the physics. Imagine you’ve built a teleportation machine that allows you to move instantly from your bedroom to your kitchen (good for late-night snacking). That’s easy enough to imagine, but now go ahead and rewrite Newton’s 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, it’s 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 stand in the kitchen and drag you there. Replace your friend with your mouse, and that’s 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 <code>Mouse</code> and <code>MouseConstraint</code>
let { Mouse, MouseConstraint } = Matter;
// Need a reference to the p5.js canvas to listen for the mouse
let canvas = createCanvas(640, 240);
// Create a <code>Matter</code> mouse attached to the native HTML5 <code>canvas</code> 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. You don’t 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>Here’s an example demonstrating a <code>MouseConstraint</code> with two <code>Box</code> objects. Static bodies act 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 this 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. What happens if you adjust these values?</p>
<h2 id="adding-more-forces">Adding More Forces</h2>
<p>In <a href="/forces#section-forces">Chapter 2</a>, I covered how to build an environment with multiple forces at play. An object might respond to gravitational attraction, wind, air resistance, and so on. Clearly, forces are at work in Matter.js as rectangles and circles spin and fly around the screen! But so far, I’ve demonstrated how to manipulate only a single global force: gravity.</p>
<pre class="codesplit" data-code-language="javascript"> let engine = Engine.create();
// Change 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 <a href="/forces#section-forces">Chapter 2</a> techniques with Matter.js, I need look no further than the trusty <code>applyForce()</code> method, which I wrote as part of the <code>Mover</code> class. It received a vector, divided it by mass, and accumulated it into the mover’s acceleration. With Matter.js, the same method exists, so I no longer need to write all the details myself! I can call it with the static <code>Body.applyForce()</code>. Here’s what that looks like in what’s now the <code>Box</code> class:</p>
<pre class="codesplit" data-code-language="javascript">class Box {
applyForce(force) {
//{!1} Call <code>Body</code>’s <code>applyForce()</code>.
Body.applyForce(this.body, this.body.position, force);
}
}</pre>
<p>Here, the <code>Box</code> class’s <code>applyForce()</code> method receives a force vector and simply passes it along to Matter.js’s <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 <a href="/forces#section-forces">Chapter 2</a>. The earlier examples assumed that the force was always applied at the mover’s center. Here, I’ve specified the exact position on the body where the force is applied. In this case, I’ve just applied it to the center as before by asking the body for its position, but this could be adjusted—for example, a force pushing at the edge of a box, causing it to spin across the canvas, much like dice tumbling when thrown.</p>
<p>How can I bring forces into a Matter.js-driven sketch? Say I want to use a gravitational attraction force. Remember the code from Example 2.6 in the <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 by 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 <code>attract()</code> 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} Use a small value for <code>G</code> to keep the system stable.
let G = 0.02;
//{!1} The mover’s mass is included here, but the attractor’s mass is left out since, as a static body, it is equivalent to infinity.
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, two other key elements are required for the sketch to behave more like the example from <a href="/forces#section-forces">Chapter 2</a>. First, remember that a Matter.js <code>Engine</code> has a default gravity pointing down. I need 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} Disable the 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>
<div class="snip-below">
<pre class="codesplit" data-code-language="javascript">class Mover {
constructor(x, y, radius) {
this.radius = radius;
//{!1} Disable the default air resistance.
let options = { frictionAir: 0 };
this.body = Bodies.circle(x, y, this.radius, options);
}</pre>
</div>
<p>This is also a good time to revisit 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.7’s <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 <a href="/autonomous-agents#section-autonomous-agents">Chapter 5</a> to Matter.js. What does flocking look like with collisions?</p>
</div>
<h2 id="collision-events">Collision Events</h2>
<p>This book isn’t called <em>The Nature of Matter.js</em>, so I’m not going to cover every possible feature of the Matter.js library. At this point, I’ve gone over the basics of creating bodies and constraints, and shown you some of what the library can do. With the skills you’ve gained, hopefully the learning process will be considerably less painful when it comes time to use an aspect of Matter.js that I haven’t addressed here. Before moving on, however, one more feature of the library is worth covering: collision events.</p>
<p>Here’s a question you’ve likely been wondering about: “What if I want something extra to happen when two bodies collide? I mean, don’t get me wrong—I’m thrilled that Matter.js is handling all the collisions behind the scenes. But if it’s taking care of the collisions for me, how am I supposed to know when they’re 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 they’re 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>That’s 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 you’re going to implement the computational geometry algorithms to test for intersection, you’re 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 you’ve 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 <code>mousePressed</code> 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 clicked. This is known as a <strong>callback</strong>, a function that’s 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. Matter.js also has 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>Just as <code>mousePressed()</code> is triggered when the mouse is clicked, <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>
<div class="avoid-break">
<pre class="codesplit" data-code-language="javascript">function handleCollisions(event) {
}</pre>
</div>
<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 a collision occurs.</p>
<p>Say I have a sketch of <code>Particle</code> objects. Each stores a reference to a Matter.js body, and I want the particles to change color when they collide. Here’s the process to follow to make that happen.</p>
<p><strong>Step 1: Event, could you tell me which two things collided?</strong></p>
<p>Now, what has collided here? Matter.js detects collisions between a pair of bodies. 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 you 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>. I’ll 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 you’re associated with?</strong></p>
<p>Getting from the relevant Matter.js bodies to the <code>Particle</code> objects they’re associated with is a little harder. After all, Matter.js doesn’t know anything about my code. Sure, it’s doing all sorts of stuff to keep track of the relationships between bodies and constraints, but it’s 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>