Introduction to Matter.js (Part 1)

As I continue on with the evolution of gamesseries, the games are getting increasingly complicated and require much of the same implementation for gravity. So for some (not all) games I will be using the Matter.js library. Matter.js is a 2D rigid body physics engine for the web, basically it’ll make much of what we do easier whilst we focus on the actual game logic.

We will still being using the p5.js library for displaying the game, but Matter.js for the actual engine.

Adding the CDN

The first thing we need to do is add the Matter.js library the latest can be found here, but you could probably just copy the code below and it’ll be fine 🙂

<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/addons/p5.dom.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/addons/p5.sound.min.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css">
   
    <!-- add the matter-js library -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.12.0/matter.min.js"></script>
    <meta charset="utf-8" />

  </head>
  <body>
    <script src="sketch.js"></script>
  </body>
</html>

Now we have access to the functions we need to make our games!

Important modules

Matter.Engine: Contains a tonne of functionality for creating and altering engines, an engine basically updates the world handling all of the functionality.

Matter.Bodies: Contains functions for creating rigid body models to add to the world.

Matter.Composite: Contains functions for manipulating composite bodies. The reference states that it is important to use the functions in this module to modify composites rather than directly modifying their properties (I learnt this the hard way).

For more information: http://brm.io/matter-js/docs/

A nice and simple example

When looking at the code below, It’s pretty simple. We create the Engine using Engine.create() and assign it the engine, we then grab the world object from the engine using engine.world, this is what we add our bodies to. We call Engine.run(engine) to start it, by default it runs at 60 ticks per second.

I have heavily commented the example below to make it easier to understand. What I recommend you doing is copying and pasting the code into the p5 editor and getting it to run. Then simply read the code from top to bottom and get a feel for it.

// just to make it easier to reference the matter library
let Engine = Matter.Engine;
let World = Matter.World;
let Bodies = Matter.Bodies;
 
let engine;
let world;
 
let circles = [];
 
let ground;
 
function setup() {
  createCanvas(400, 400);
 
  // create an engine
  engine = Engine.create();
  world = engine.world;
   
  // is static means it is not affected by gravity
  let groundParams = {
    isStatic: true
  }
  // creates a rectangle body
  ground = Bodies.rectangle(width / 2, height - 10, width * 2, 20, groundParams);
    
  // creates some circle bodies 
  let ballParams = {
  	restitution: 0.5,
    frictionAir: 0.06
  }
  
  for (let i = 0; i < 100; i++) {
    circles.push(Bodies.circle(random(width), random(-1000, 40), 10, ballParams));
  }
   
  // adding the circles and ground to the world
  World.add(world, circles);
  World.add(world, ground);
   
  // run the engine
  Engine.run(engine);
   
  console.log(ground);
}
 
function draw() {
  background(255);
   
  // drawing the circles
  fill(255,105,180);
  for (let circle of circles) {
    ellipse(circle.position.x, circle.position.y, 20);
  }
   

  fill(200);
  // the Matter.js uses the mid point of a rectangle as the reference point
  rectMode(CENTER);
  rect(ground.position.x, ground.position.y, width * 2, 20);
}


When creating the ground/circles we pass it an extra (optional) parameter for options, there are many things we can add, here are a few examples that I regularly use (here for the reference):

  • density (Default: 0.001)
  • force (Default: {x : 0, y : 0})
  • friction (Default: 0.1)
  • frictionAir (Default: 0.1)
  • isStatic (Default: False)

Adding to our example

As a nice test to get to grips with the Matter.js library I’m going to alter the game such that there will be a gap in the ground and if balls go through that gap then they will respawn in a random location and if they go off the side they’ll pop to the other side. I highly recommend you having a go at this before looking at my code below 😀

First step, let’s add the hole

We create an array of grounds, probably a little overkill as we only need to grounds but hey.

// just to make it easier to reference the matter library
let Engine = Matter.Engine;
let World = Matter.World;
let Bodies = Matter.Bodies;
 
let engine;
let world;
 
let circles = [];
 
let grounds = [];

const GROUND_WIDTH = 300;
 
function setup() {
  createCanvas(400, 400);
 
  // create an engine
  engine = Engine.create();
  world = engine.world;
   
  // is static means it is not affected by gravity
  let groundParams = {
    isStatic: true
  }
  // creates the two grounds
  grounds.push(Bodies.rectangle(0, height - 10, GROUND_WIDTH, 20, groundParams));
  grounds.push(Bodies.rectangle(width, height - 10, GROUND_WIDTH, 20, groundParams));
    
  // creates some circle bodies 
  let ballParams = {
  	restitution: 0.5,
    frictionAir: 0.06
  }
  
  for (let i = 0; i < 100; i++) {
    circles.push(Bodies.circle(random(width), random(-1000, 40), 10, ballParams));
  }
   
  // adding the circles and ground to the world
  World.add(world, circles);
  World.add(world, grounds);
   
  // run the engine
  Engine.run(engine);

}
 
function draw() {
  background(255);
   
  // drawing the circles
  fill(255,105,180);
  for (let circle of circles) {
    ellipse(circle.position.x, circle.position.y, 20);
  }
   

  fill(200);
  // the Matter.js uses the mid point of a rectangle as the reference point
  rectMode(CENTER);
  
  for (let ground of grounds) {
    rect(ground.position.x, ground.position.y, GROUND_WIDTH, 20);
  }

}


Let’s wrap it!

Okay, so I’ll be completely honest, I cheated a little here. I struggled a little to get this to work and had a bit of a google. I found that people who had done something like this had used another library called matter-wrap.js which is written by the same bloke.

// setup wrap coordinates plugin
Matter.use('matter-wrap');

// just to make it easier to reference the matter library
let Engine = Matter.Engine;
let World = Matter.World;
let Bodies = Matter.Bodies;
 
let engine;
let world;
 
let circles = [];
 
let grounds = [];

const GROUND_WIDTH = 300;
 
function setup() {
  createCanvas(400, 400);
 
  // create an engine
  engine = Engine.create();
  world = engine.world;
   
  // is static means it is not affected by gravity
  let groundParams = {
    isStatic: true
  }
  // creates the two grounds
  grounds.push(Bodies.rectangle(0, height - 10, GROUND_WIDTH, 20, groundParams));
  grounds.push(Bodies.rectangle(width, height - 10, GROUND_WIDTH, 20, groundParams));
    
  // creates some circle bodies 
  let ballParams = {
  	restitution: 0.5,
    frictionAir: 0.06
  }
  
  for (let i = 0; i < 100; i++) {
    let circle = Bodies.circle(random(width), random(-1000, 40), 10, ballParams);
    // set the wrap, so it goes off the screen it reappears
    circle.plugin.wrap = {
      min: { x: 0, y: 0 },
      max: { x: width, y: height }
    };
    circles.push(circle);
  }
   
  // adding the circles and ground to the world
  World.add(world, circles);
  World.add(world, grounds);
   
  // run the engine
  Engine.run(engine);

}
 
function draw() {
  background(255);
   
  // drawing the circles
  fill(255,105,180);
  for (let circle of circles) {
    ellipse(circle.position.x, circle.position.y, 20);
  }
   

  fill(200);
  // the Matter.js uses the mid point of a rectangle as the reference point
  rectMode(CENTER);
  
  for (let ground of grounds) {
    rect(ground.position.x, ground.position.y, GROUND_WIDTH, 20);
  }

}


Finally

Have a play around with the code, change some parameters and really get a feel for it. In next weeks tutorial we’ll be going over more advanced topics like rotations, applying forces to bodies and mouse interaction.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s