'How to create a random ground in matter.js

I am creating the ground of a game using a Perlin noise function. This gives me an array of vertices. I then add a vertex at the front that is {x:0 y: WORLD_HEIGHT} and another at the end of the array that is {x: WORLD_WIDTH y: WORLD_HEIGHT}. I am hoping that will give me a flat base with a random top.

How then do I add this into the matter.js world? I am trying to create the ground using;

var terrain = Bodies.fromVertices(???, ???, vertexSets, {
    isStatic: true
}, true); 

but I don't know what to use for the ??? co-ordinates. I think they are supposed to represent the center of the object. However, I don't know what that is because it is noise. What I would like to do is specify the x & y of the first perlin noise vertex.

I am not even sure that given these vertices matter.js is creating a single body or multiple.

Is this the right way to approach it or there another way to do this? I am really struggling with the docs and the examples.



Solution 1:[1]

I use Matter.Body.setPosition(body, position) to override the center of mass and put the ground where I want it based on its bounds property.

const engine = Matter.Engine.create();
const render = Matter.Render.create({
  element: document.body,
  engine: engine,
});
const w = 300;
const h = 300;

const vertices = [
  ...[...Array(16)].map((_, i) => ({
    x: i * 20,
    y: ~~(Math.random() * 40),
  })),
  {x: w, y: 100},
  {x: 0, y: 100},
];
const ground = Matter.Bodies.fromVertices(
  w - 10, h - 10, // offset by 10 pixels for illustration
  vertices,
  {isStatic: true},
  /* flagInternal =*/ true,
);

Matter.Body.setPosition(ground, {
  x: w - ground.bounds.min.x,
  y: h - ground.bounds.max.y + 110,
});

const {min: {x}, max: {y}} = ground.bounds;
console.log(x, y); // 10 120

Matter.Composite.add(engine.world, [ground]);
Matter.Render.run(render);
Matter.Runner.run(engine);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/decomp.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.18.0/matter.min.js"></script>

Without setPosition, you can see things jump around if you run this snippet a few times (just to reproduce OP's error with a concrete example):

const engine = Matter.Engine.create();
const render = Matter.Render.create({
  element: document.body,
  engine: engine,
});

const vertices = [
  ...[...Array(16)].map((_, i) => ({
    x: i * 20,
    y: ~~(Math.random() * 40),
  })),
  {x: 300, y: 100},
  {x: 0, y: 100},
];
const ground = Matter.Bodies.fromVertices(
  200, 100, vertices,
  {isStatic: true}, 
  /* flagInternal =*/ true,
);

Matter.Composite.add(engine.world, [ground]);
Matter.Render.run(render);
Matter.Runner.run(engine);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/decomp.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.18.0/matter.min.js"></script>

I'm not using Perlin noise and there are some internal vertices that aren't properly detected in the above examples, but the result should be the same either way.

Solution 2:[2]

should be integers, all width and height of the noise texture. values at those x, y integer places can be floats... no problem.

and same width and height should go to terrain and values at that places will be the height of the terrain.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2