为什么 MatterJS 物理坐标与 DOM 元素有偏移?

问题描述

我通过向物理引擎添加框来运行 MatterJS 物理模拟,同时创建具有相同尺寸的 DOM 元素。

然后,我将遍历物理框以获取它们的坐标。然后我使用这些坐标来定位相应的 DOM 元素。这似乎工作正常,除了我的静态“地面”框似乎有一个 10 像素的不可见半径围绕它?

我的盒子是 40x40 像素。地面为 400 像素。盒子在 350 像素处停止下降。那么为什么会有 10 个像素的差异呢?

Here is an example of the issue in CodePen

编辑:如果我在画布中渲染相同的框,则不存在差异。 Codepen Canvas

class Box {
  constructor(world,x,y,w,h,options) {
    // add Box to physics simulation
    this.physicsBox = Matter.Bodies.rectangle(x,options);
    Matter.Composite.add(world,this.physicsBox);

    // add DOM Box at the same coordinates
    this.div = document.createElement("Box");
    document.body.appendChild(this.div);
    this.div.style.width = w + "px";
    this.div.style.height = h + "px";
    this.update();
  }

  update() {
    let pos = this.physicsBox.position;
    let angle = this.physicsBox.angle;
    let degrees = angle * (180 / Math.PI);
    this.div.style.transform = `translate(${pos.x}px,${pos.y}px) rotate(${degrees}deg)`;
  }
}

let engine;
let Boxes = [];

setupMatter();
addobjects();
gameLoop();

function setupMatter() {
  engine = Matter.Engine.create();
}

function addobjects() {
  Boxes.push(
    new Box(engine.world,250,20,40,40),new Box(engine.world,300,350,320,70,400,800,60,{ isstatic: true })
  );
}

function gameLoop() {
  // update the physics world
  Matter.Engine.update(engine,1000 / 60);
  // update the DOM world
  for (let b of Boxes) {
    b.update();
  }
  requestAnimationFrame(() => this.gameLoop());
}
html,body {
  background-color: #4b4b4b;
  color: white;
  margin: 0px;
  padding: 0px;
}

Box {
  margin: 0px;
  padding: 0px;
  Box-sizing: border-Box;
  position: absolute;
  display: block;
  background-color: rgba(45,188,232,0.687);
  transform-origin: 20px 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.17.1/matter.min.js"></script>

解决方法

问题在于,当您为框设置 x,y 位置时,您没有考虑高度。所以显示的位置与实际位置不匹配。

我真正改变的唯一一行是 this.div.style.transform = `translate(${pos.x}px,${pos.y}px) rotate(${degrees}deg)`;

10 像素的差异是因为 60 像素深的底部显示的 30 像素(深度的一半)太低,而 40 像素深的框显示的太低 20 像素 - 底部上方的净 10 像素。当我尝试将高度设置为 1px 时,一切看起来都不错,这就是我发现错误的方式。

class Box {
  constructor(world,x,y,w,h,options) {
    // add box to physics simulation
    this.physicsBox = Matter.Bodies.rectangle(x,options);
    Matter.Composite.add(world,this.physicsBox);

    // add DOM box at the same coordinates
    this.div = document.createElement("box");
    document.body.appendChild(this.div);
    this.div.style.width = w + "px";
    this.div.style.height = h + "px";
    this.width = w;
    this.height = h;
    this.update();
  }

  update() {
    let pos = this.physicsBox.position;
    let angle = this.physicsBox.angle;
    let degrees = angle * (180 / Math.PI);
    this.div.style.transform = `translate(${pos.x - (this.width/2)}px,${pos.y-(this.height/2)}px) rotate(${degrees}deg)`;
  }
}

let engine;
let boxes = [];

setupMatter();
addObjects();
gameLoop();

function setupMatter() {
  engine = Matter.Engine.create();
}

function addObjects() {
  boxes.push(
    new Box(engine.world,250,20,40,40),new Box(engine.world,300,350,320,70,400,800,60,{ isStatic: true })
  );
}

function gameLoop() {
  // update the physics world
  Matter.Engine.update(engine,1000 / 60);
  // update the DOM world
  for (let b of boxes) {
    b.update();
  }
  requestAnimationFrame(() => this.gameLoop());
}
html,body {
  background-color: #4b4b4b;
  color: white;
  margin: 0px;
  padding: 0px;
}

box {
  margin: 0px;
  padding: 0px;
  box-sizing: border-box;
  position: absolute;
  display: block;
  background-color: rgba(45,188,232,0.687);
  transform-origin: 20px 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.17.1/matter.min.js"></script>