Will Boyd
May 18, 2018
7.9k

# Exploring 2D Physics in JavaScript

Let's play with physics in JavaScript! This talk will introduce you to Matter.js, an open source physics engine powered by JavaScript. You'll learn how to create fun and interesting physics-based interactions, even if you have no prior experience. By the end of the talk, you'll be ready to create your own physics-based demos, games, and web page interactions.

Demos for this talk can be viewed here: https://lonekorean.github.io/javascript-physics/.

All source code is available here: https://github.com/lonekorean/javascript-physics.

May 18, 2018

## Transcript

1. EXPLORING
2D PHYSICS
IN JAVASCRIPT
WILL BOYD @lonekorean

2. BODIES WORLD ENGINE RUNNER RENDER

3. BODIES WORLD ENGINE RUNNER RENDER

The physical objects that are
being simulated

4. The collection of bodies in a
shared space
BODIES WORLD ENGINE RUNNER RENDER

5. BODIES WORLD ENGINE RUNNER RENDER

world

6. BODIES WORLD ENGINE RUNNER RENDER

7. BODIES WORLD ENGINE RUNNER RENDER

Visualizes the output of the
engine as a element

8. Minimal Setup

Minimal HTML

9. // engine
let engine = Matter.Engine.create();
// render
let render = Matter.Render.create({
element: document.body,
engine: engine
});
Matter.Render.run(render);
// runner
let runner = Matter.Runner.create();
Matter.Runner.run(runner, engine);
Basic Setup

10. // params: x, y, radius
let ball = Matter.Bodies.circle(400, 100, 50);
Simple Body

11. y
x
(0, 0)

12. ( , )
y
x

13. Matter.Bodies.rectangle(x, y, width, height);
( , )
y
x
width
height

14. DEMO TIME!
MINIMAL SETUP

15. Matemateca (IME/USP)/Rodrigo Tetsuo Argenton
CC-BY-SA 4.0
LET’S MAKE
A GALTON BOARD!

16. BOUNDARY WALLS

17. BOUNDARY WALLS
DIVIDER WALLS

18. BOUNDARY WALLS
DIVIDER WALLS
PEGS

19. BOUNDARY WALLS
DIVIDER WALLS
PEGS

20. let render = Matter.Render.create({
element: document.body,
engine: engine,
options: {
width: 560,
height: 800,
background: ‘#f8f9fa',
wireframes: false
}
});
Setting Render Options

21. // params: x, y, width, height, options
let bottom = Matter.Bodies.rectangle(280, 800, 560, 20, {
isStatic: true,
render: {
fillStyle: '#868e96'
}
});

22. function wall(x, y, width, height) {
return Matter.Bodies.rectangle(x, y, width, height, {
isStatic: true,
render: {
fillStyle: '#868e96'
}
});
}
Abstracting Wall Creation

wall(280, 0, 560, 20), // top
wall(280, 800, 560, 20), // bottom
wall(0, 400, 20, 800), // left
wall(560, 400, 20, 800), // right
]);

24. for (let x = 0; x <= 560; x += 80) {
let divider = wall(x, 610, 20, 360);
}

25. function peg(x, y) {
return Matter.Bodies.circle(x, y, 14, {
isStatic: true,
render: {
fillStyle: '#82c91e'
}
});
}
Peg Creation

26. let isStaggerRow = false;
for (let y = 200; y <= 400; y += 40) {
let startX = isStaggerRow ? 80 : 40;
for (let x = startX; x <= 520; x+= 80) {
}
isStaggerRow = !isStaggerRow;
}
Field Of Pegs

return Matter.Bodies.circle(280, 40, 11, {
render: {
fillStyle: '#e64980'
}
});
}

}

29. DEMO TIME!
GALTON BOARD (ROUND 1)

30. Matter.Common.random(min, max);
function rand(min, max) {
return Math.random() * (max - min) + min;
}
Randomness
- vs -

x: rand(-0.05, 0.05),
y: 0
});
}
Making Things Less Perfect

x: rand(-0.05, 0.05),
y: 0
});
}
Making Things Less Perfect

33. function peg(x, y) {
return Matter.Bodies.circle(x, y, 14, {
restitution: 0.5,
// other properties here...
});
}
return Matter.Bodies.circle(280, 40, 11, {
restitution: 0.5,
// other properties here...
});
}

34. function peg(x, y) {
return Matter.Bodies.circle(x, y, 14, {
label: 'peg',
// other properties here...
});
}
Peg Labels

35. Matter.Events.on(engine, ‘collisionStart', lightPeg);
function lightPeg(event) {
event.pairs
.filter((pair) => pair.bodyA.label === 'peg')
.forEach((pair) => {
pair.bodyA.render.fillStyle = '#4c6ef5';
});
}
Lighting Up Pegs

36. Matter.Events.on(engine, ‘collisionStart', lightPeg);
function lightPeg(event) {
event.pairs
.filter((pair) => pair.bodyA.label === 'peg')
.forEach((pair) => {
pair.bodyA.render.fillStyle = '#4c6ef5';
});
}
Lighting Up Pegs

37. Matter.Events.on(engine, ‘collisionStart', lightPeg);
function lightPeg(event) {
event.pairs
.filter((pair) => pair.bodyA.label === 'peg')
.forEach((pair) => {
pair.bodyA.render.fillStyle = '#4c6ef5';
});
}
Lighting Up Pegs

38. DEMO TIME!
GALTON BOARD (ROUND 2)

DEBUGGING
WITH MATTER TOOLS!

40. DEMO TIME!
MATTER TOOLS

41. Matter Tools

Matter Tools HTML

42. function initGaltonBoard() {
// existing code goes here...
return {
engine: engine,
render: render,
canvas: render.canvas,
runner: runner,
stop: function() {
Matter.Render.stop(render);
Matter.Runner.stop(runner);
}
};
}
Repackage Existing Code

43. MatterTools.Demo.create({
appendTo: document.body,
tools: { gui: true },
examples: [
{
id: 'galton-board',
init: initGaltonBoard,
}
]
});
Matter Tools Setup

44. MatterTools.Demo.create({
appendTo: document.body,
tools: { gui: true },
examples: [
{
id: 'galton-board',
init: initGaltonBoard,
}
]
});
Matter Tools Setup

45. let mouseConstraint = Matter.MouseConstraint.create(engine, {
mouse: Matter.Mouse.create(render.canvas)
});
Mouse Control

46. DEMO TIME!
LIGHTNING ROUND

47. DEMO TIME!
PINBALL

48. ATTRACTORS + COLLISION FILTERS

49. ATTRACTORS + COLLISION FILTERS
CONSTRAINTS

50. ATTRACTORS + COLLISION FILTERS
CONSTRAINTS
COMPOSITES

51. DEMO TIME!
PAGE INTERACTIONS

52. THANKS!
WILL BOYD @lonekorean
★ brm.io/matter-js/
★ lonekorean.github.io/javascript-physics/