2

I am using Matter.js to build games. Starting from one of their examples: Pyramid, I started playing around. The code fro this specific example is as follows:

var Example = Example || {};

Example.pyramid = function() {
    var Engine = Matter.Engine,
        Render = Matter.Render,
        Runner = Matter.Runner,
        Composites = Matter.Composites,
        MouseConstraint = Matter.MouseConstraint,
        Mouse = Matter.Mouse,
        World = Matter.World,
        Bodies = Matter.Bodies;

    // create engine
    var engine = Engine.create(),
        world = engine.world;

    // create renderer
    var render = Render.create({
        element: document.body,
        engine: engine,
        options: {
            width: 800,
            height: 600,
            showAngleIndicator: true
        }
    });

    Render.run(render);

    // create runner
    var runner = Runner.create();
    Runner.run(runner, engine);

    // add bodies
    var stack = Composites.pyramid(100, 258, 15, 10, 0, 0, function(x, y) {
        return Bodies.rectangle(x, y, 40, 40);
    });

    World.add(world, [
        stack,
        // walls
        Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
        Bodies.rectangle(800, 300, 50, 600, { isStatic: true }),
        Bodies.rectangle(0, 300, 50, 600, { isStatic: true }),
        Bodies.rectangle(400, 605, 800, 50, { isStatic: true })
    ]);

    // add mouse control
    var mouse = Mouse.create(render.canvas),
        mouseConstraint = MouseConstraint.create(engine, {
            mouse: mouse,
            constraint: {
                stiffness: 0.2,
                render: {
                    visible: false
                }
            }
        });

    World.add(world, mouseConstraint);

    // keep the mouse in sync with rendering
    render.mouse = mouse;

    // fit the render viewport to the scene
    Render.lookAt(render, {
        min: { x: 0, y: 0 },
        max: { x: 800, y: 600 }
    });

    // context for MatterTools.Demo
    return {
        engine: engine,
        runner: runner,
        render: render,
        canvas: render.canvas,
        stop: function() {
            Matter.Render.stop(render);
            Matter.Runner.stop(runner);
        }
    };
};

I am trying to modify the code in order to disallow the sprites in the pyramid to be moved by mouse. The part of code responsible for creating those objects is this:

// add bodies
var stack = Composites.pyramid(100, 258, 15, 10, 0, 0, 
  function(x, y) {
    return Bodies.rectangle(x, y, 40, 40);
  });

I have tried searching among the options that can be passed to Bodies.rectangle, but found nothing.

How to achieve this?

Andry
  • 16,172
  • 27
  • 138
  • 246

1 Answers1

0

You can use the collisionFilter property to do this.

Collision filters use groups, masks and categories to determine which bodies collide. I'll ignore groups in this example. By default, bodies belong to category 1 and have all masked enabled:

const objValsToBase = (o, base) =>
  Object.fromEntries(Object.entries(o)
    .map(([k, v]) => [k, v.toString(base)]));

const circle = Matter.Bodies.circle(200, 100, 50);

// show decimal (base 10)
console.log(circle.collisionFilter);

// show bits (base 2)
console.log(objValsToBase(circle.collisionFilter, 2));

// show hex (base 16)
console.log(objValsToBase(circle.collisionFilter, 16));
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script>

To get two bodies to stop colliding, you can set the category on one group to 0b10, which is 0x2 in hex and 2 in decimal, and set the mask on the other to turn off the 2 bit: 0b01. 0b01 also disables collisions you might have with other categories which are unused by default but might be used in your code sooner or later, so you might prefer 0xfffffd since (0xd).toString(2) => '1101'.

Below is the pyramid example code modified to disable mouse-pyramid collision. I also ran it through prettier and added a circle that collides with everything to show that the mouse still works on that:

var Engine = Matter.Engine,
  Render = Matter.Render,
  Runner = Matter.Runner,
  Composites = Matter.Composites,
  MouseConstraint = Matter.MouseConstraint,
  Mouse = Matter.Mouse,
  World = Matter.World,
  Bodies = Matter.Bodies;

// create engine
var engine = Engine.create(),
  world = engine.world;

// create renderer
var render = Render.create({
  element: document.body,
  engine: engine,
  options: {
    width: 800,
    height: 600,
    showAngleIndicator: true,
  },
});

Render.run(render);

// create runner
var runner = Runner.create();
Runner.run(runner, engine);

// add bodies
var stack = Composites.pyramid(
  100,
  258,
  15,
  10,
  0,
  0,
  function (x, y) {
    return Bodies.rectangle(x, y, 40, 40, {
      collisionFilter: {mask: 0xfffffd}, // <--
    });
  }
);

World.add(world, [
  stack,
  // walls
  Bodies.circle(200, 100, 50),
  Bodies.rectangle(400, 0, 800, 50, {isStatic: true}),
  Bodies.rectangle(800, 300, 50, 600, {isStatic: true}),
  Bodies.rectangle(0, 300, 50, 600, {isStatic: true}),
  Bodies.rectangle(400, 605, 800, 50, {isStatic: true}),
]);

// add mouse control
var mouse = Mouse.create(render.canvas),
  mouseConstraint = MouseConstraint.create(engine, {
    mouse: mouse,
    collisionFilter: {category: 0b10}, // <--
    constraint: {
      stiffness: 0.2,
      render: {
        visible: false,
      },
    },
  });

World.add(world, mouseConstraint);

// keep the mouse in sync with rendering
render.mouse = mouse;

// fit the render viewport to the scene
Render.lookAt(render, {
  min: {x: 0, y: 0},
  max: {x: 800, y: 600},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script>

See also:

ggorlen
  • 44,755
  • 7
  • 76
  • 106