Search code examples
javascriptp5.jsmatter.js

Matter.Query.region not returning any collisions even though the bound is clearly intersecting other bodies


I'm trying to use Matter.Query.region to see if the character in my game is grounded. But, when I try to run region with a bounds object that I created (displayed with the dots shown in the game), it doesn't come up with any collisions even though it is clearly intersecting other bodies.

Code:

let Engine = Matter.Engine,
    Runner = Matter.Runner,
    World = Matter.World,
    Bodies = Matter.Bodies,
    Body = Matter.Body,
    Composite = Matter.Composite;

let engine;

let boxA;
let boxB;
let platforms = [];

function setup() {
  createCanvas(550, 400);

  // create an engine
  engine = Engine.create();

  // create two boxes and a ground
  boxA = Bodies.rectangle(275, 200, 80, 80, {
    mass: 20
  });
  platforms.push(boxA);

  boxB = Bodies.rectangle(300, 50, 80, 80, {
    mass: 20
  });
  Body.setInertia(boxB, Infinity);
  
  ground = Bodies.rectangle(250, 410, 810, 60, {
    isStatic: true
  });
  platforms.push(ground);

  // add all of the bodies to the world
  World.add(engine.world, [boxA, boxB, ground]);

  let runner = Runner.create();
  Runner.run(runner, engine);
}

// Using p5 to render
function draw() {
  let add = Matter.Vector.add; // alias

  let leeway = {x: 0, y: 30}
  let topLeft = {x: boxB.position.x - 40, y: boxB.position.y + 40}
  let topRight = add(topLeft, {x: 80, y: 0});
  let bottomLeft = add(topLeft, leeway);
  let bottomRight = add(topRight, leeway);

  let bounds = Matter.Bounds.create(topLeft, topRight, bottomRight, bottomLeft);
  let query = Matter.Query.region(platforms, bounds);
  
  console.log(Matter.Bounds.overlaps(bounds, boxA.bounds), query);

  background(51);
  keyDown();
  
  drawShape(boxA);
  drawShape(boxB);
  drawShape(ground, 127);

  push();
  // Show bounds
  stroke('purple');
  strokeWeight(10);
  point(topLeft.x, topLeft.y);
  point(topRight.x, topRight.y);
  point(bottomLeft.x, bottomLeft.y);
  point(bottomRight.x, bottomRight.y);
  pop();
}

function drawShape(body, color = 225) {
  beginShape();
  fill(color);
  for (let vertice of body.vertices) {
    vertex(vertice.x, vertice.y);
  }
  endShape();
}

function keyPressed() {
  let jumpHeight = 14;
  
  if (keyCode === UP_ARROW) {
    Body.setVelocity(boxB, {x:boxB.velocity.x, y:-jumpHeight})
  }
}
function keyDown() {
  let velocity = 12;
  let targetX = boxB.velocity.x;

  if (keyIsDown(RIGHT_ARROW)) {
    targetX = velocity;
  } else if (keyIsDown(LEFT_ARROW)) {
    targetX = -velocity;
  } else {
    targetX = 0;
  }
  targetX = lerp(boxB.velocity.x, targetX, 0.1);
  Body.setVelocity(boxB, {x: targetX, y: boxB.velocity.y});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.18.0/matter.min.js" integrity="sha512-5T245ZTH0m0RfONiFm2NF0zcYcmAuNzcGyPSQ18j8Bs5Pbfhp5HP1hosrR8XRt5M3kSRqzjNMYpm2+it/AUX/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

Full code: https://replit.com/@CrazyVideoGamer/MatterQueryregion-not-working#sketch.js

By the way, the character is the variable boxB, and you can move with the arrow keys.


Solution

  • The bounds object doesn't appear to be properly created. The purple p5 vertices you're rendering may be giving you a false sense of confidence, since those aren't necessarily related to what MJS sees.

    It's actually a pretty simple fix, passing an array of vertices instead of individual arguments:

    let bounds = Matter.Bounds.create([topLeft, topRight, bottomRight, bottomLeft]);
    //                                ^                                          ^
    

    I wound up cleaning things up a bit in the process of debugging and made the collision easier to visualize without the console. Feel free to use some of this code if you need or just make the one change as you see fit.

    const {Engine, Runner, Composite, Bodies, Body} = Matter;
    let engine;
    let boxA;
    let boxB;
    const platforms = [];
    
    function setup() {
      createCanvas(550, 400);
      engine = Engine.create();
    
      // create two boxes and a ground
      boxA = Bodies.rectangle(275, 200, 80, 80, {
        mass: 20
      });
      platforms.push(boxA);
    
      boxB = Bodies.rectangle(300, 50, 80, 80, {
        mass: 20
      });
      Body.setInertia(boxB, Infinity); // TODO remove for realism
      
      ground = Bodies.rectangle(250, 410, 810, 60, {
        isStatic: true
      });
      platforms.push(ground);
      Composite.add(engine.world, [boxA, boxB, ground]);
      Runner.run(Runner.create(), engine);
    }
    
    function draw() {
      const {x, y} = boxB.position;
      const vertices = [
        // FIXME hardcoded values for now...
        {x: x - 40, y: y + 40},
        {x: x + 40, y: y + 40},
        {x: x + 40, y: y + 50},
        {x: x - 40, y: y + 50},
      ];
      const bounds = Matter.Bounds.create(vertices, boxB);
      
      // return valaue holds the collided platform(s)
      const collisions = Matter.Query.region(platforms, bounds);
    
      background(51);
      keyDown();
      
      drawShape(boxA);
      drawShape(boxB);
      drawShape(ground, 127);
    
      push();
      // Show bounds collision
      stroke(collisions.length ? 'red' : 'purple');
      strokeWeight(10);
      vertices.forEach(({x, y}) => point(x, y));
      pop();
    }
    
    function drawShape(body, color=225) {
      beginShape();
      fill(color);
      body.vertices.forEach(({x, y}) => vertex(x,  y));
      endShape();
    }
    
    function keyPressed() {
      const jumpHeight = 14;
      
      if (keyCode === UP_ARROW) {
        Body.setVelocity(boxB, {x: boxB.velocity.x, y: -jumpHeight})
      }
    }
    
    function keyDown() {
      const velocity = 12;
      let targetX = 0;
    
      if (keyIsDown(RIGHT_ARROW)) {
        targetX = velocity;
      } else if (keyIsDown(LEFT_ARROW)) {
        targetX = -velocity;
      }
      
      targetX = lerp(boxB.velocity.x, targetX, 0.1);
      Body.setVelocity(boxB, {x: targetX, y: boxB.velocity.y});
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.4/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.20.0/matter.min.js"></script>