Use object layers of tilemap for collision detection

Hello, as the picture shows below, I have an object layer and there are many shapes for collision detection in this layer (the gray line)


How can I convert these shapes to some Phaser 3 objects for the collision detection ?
I find a related example: set colliding by collison data

// Instead of setting collision by index, you can set any tile that has collision data to
        // collide. Typically, this is done in the Tiled collision editor. All tiles in this layer have
        // collision shapes.
        this.layer.setCollisionFromCollisionGroup();

        this.shapeGraphics = this.add.graphics();
        this.drawCollisionShapes(this.shapeGraphics);

        this.matter.world.convertTilemapLayer(this.layer);
        this.matter.world.setBounds(map.widthInPixels, map.heightInPixels);

However, it’s not the same as my case, there is only a single layer in this map. And it seems that the collision shape is calculated from the tiles’ boundaries by matter engine, instead of getting directly from the data of tilemap.

In my map, there is an object layers storing the shapes for colliding


In this map, there is a single layer

It seems that there is no collision group or anything like that.

You could convert the rectangles into Arcade Physics zone game objects and add colliders as usual.

Thanks.
But the Arcade can only handle the collision between rectangles, right ?
I tried Matter.js, I find that the geometry objects created by this.matter.add will be displayed only if a debug property is set in the game configuration. Can I use them to achieve collision detection (with the debug off) ? Will they be rendered if I turn the debug off ?

I am trying to use matter.js, but the shapes it create does not work as I expected :frowning:
I want to draw a rectangle and rotate it by 45 degree, However, b.angle does not change the angle of the rectangle.

let b = this.matter.add.rectangle(500, 200, 50, 50, {isStatic: true});
b.render.lineColor = 0xff0000;
b.render.lineThickness = 2;
b.angle = 45 * Math.PI / 180.0;
// If I don't set anglePrev, angularSpeed and angularVelocity
// will automatically equal to b.angle, this makes the rectangle spins 
// It is quite strange to me.
b.anglePrev = 45 * Math.PI / 180.0;

The shape isn’t rotated.
image
Do you have any idea where I did wrong ? Thanks a lot.

I looked through the tutorials of matter.js, the angle can be set correctly if I set the angle in the configuration:

let b = this.matter.add.rectangle(500, 200, 50, 50, { isStatic: true, angle: Math.PI * 0.06, render: { fillStyle: 0xff0000 }});
b.render.lineColor = 0xff0000;
b.render.lineThickness = 2;

However, some properties still can be set correctly, for example, the fillStyle.

You could do something like this in your scene. Iterate over objects and handle circles, rectangles and polygons accordingly. Suggest using polygons instead of rotating and combining rectangles. You can pass Tiled polygons into matter.js by mapping their vertices to a string and using “fromVertices” (see below).

function getVertices(items: Phaser.Types.Math.Vector2Like[]) {
  return items.reduce((accumulator, item, index) => {
    return `${accumulator}${item.x} ${item.y} `;
  }, "").slice(0, -1);
}

const objectLayer = tilemap.getObjectLayer("NAME_OF_OBJECT_LAYER");

objectLayer.objects.forEach((object) => {
  if (object.ellipse) {
    this.matter.add.circle(object.x + object.width / 2, object.y + object.height / 2, object.width / 2, {
      isStatic: true,
    });
  } else if (object.rectangle) {
    this.matter.add.rectangle(
      object.x + object.width / 2,
      object.y + object.height / 2,
      object.width,
      object.height,
      {
        isStatic: true,
      }
    );
  } else if (object.polygon) {
    const vertices = getVertices(object.polygon);
    const polygon = this.add.polygon(object.x, object.y, vertices);
    const gameObject = this.matter.add.gameObject(polygon, {
      isStatic: true,
      shape: {
        type: "fromVertices",
        verts: vertices,
      },
    }) as Phaser.Physics.Matter.Image;
    const body = polygon.body as MatterJS.BodyType;

    gameObject.setPosition(polygon.x + body.centerOffset.x, polygon.y + body.centerOffset.y);
  }
});
2 Likes

Thanks for your answer ! :grinning:

1 Like