首页 > 解决方案 > 为什么 MatterJS 物理坐标与 DOM 元素有偏移?

问题描述

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

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

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

这是 CodePen 中的问题示例

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

class Box {
  constructor(world, x, y, w, h, options) {
    // add box to physics simulation
    this.physicsBox = Matter.Bodies.rectangle(x, y, w, h, 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, 40, 40),
    new Box(engine.world, 320, 70, 40, 40),
    new Box(engine.world, 0, 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>

标签: javascriptphysicsmatter.js

解决方案


问题是,当您为盒子设置 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, y, w, h, 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, 40, 40),
    new Box(engine.world, 320, 70, 40, 40),
    new Box(engine.world, 0, 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>


推荐阅读