Matter.js中的自定义元素 反应

问题描述

Kinda坚持使用Matter.js,希望能获得一些帮助。

我想在Matter.js中将自定义html元素呈现为实体

(我在React中使用它会增加一些复杂性,但这与我的问题无关)

我进行了很多搜索,发现的唯一示例是this one here。似乎是将查询选择器用于HTML代码中的那些元素,然后以某种方式在矩形形状中使用它们。

似乎可以完成工作的部分如下:

var bodiesDom = document.querySelectorAll('.block');
var bodies = [];
for (var i = 0,l = bodiesDom.length; i < l; i++) {
    var body = Bodies.rectangle(
        VIEW.centerX,20,VIEW.width*bodiesDom[i].offsetWidth/window.innerWidth,VIEW.height*bodiesDom[i].offsetHeight/window.innerHeight
    );
    bodiesDom[i].id = body.id;
    bodies.push(body);
}
World.add(engine.world,bodies);

(VIEW变量定义形状时可能只是随机数)

但是,我无法理解如何像上面的示例一样在Bodies矩形内传递HTML元素。

理想情况下,我想让复杂的HTML元素与物理世界互动(例如带有按钮等的小盒子)

关于如何实现此目标的任何想法?还是至少可以理解在示例中使用的似乎可以管理它的方法

解决方法

但是,我无法理解如何像上面的示例一样在Bodies矩形内传递HTML元素。

这与示例的功能完全不同。当无头运行时,Matter.js会处理物理,但不知道其渲染方式。对于每个动画帧,您可以使用MJS主体的当前位置并重新放置元素(或在画布上绘制等)以反映MJS的世界观。

为MJS提供根元素似乎确实打破了单向数据流,但这仅是为了向MJS通知诸如鼠标位置和点击之类的事件-请勿与渲染混淆。

下面是一个最小的示例,希望可以使它变得更清楚:

const engine = Matter.Engine.create();  
const box = {
  body: Matter.Bodies.rectangle(150,40,40),elem: document.querySelector("#box"),render: function () {
    const {x,y} = this.body.position;
    this.elem.style.top = `${y - 20}px`;
    this.elem.style.left = `${x - 20}px`;
    this.elem.style.transform = `rotate(${this.body.angle}rad)`;
  },};
const ground = Matter.Bodies.rectangle(
  200,200,400,120,{isStatic: true}
);
const mouseConstraint = Matter.MouseConstraint.create(
  engine,{element: document.body}
);
Matter.World.add(
  engine.world,[box.body,ground,mouseConstraint]
);
(function rerender() {
  box.render();
  Matter.Engine.update(engine);
  requestAnimationFrame(rerender);
})();
#box {
  position: absolute;
  background: #111;
  height: 40px;
  width: 40px;
  cursor: move;
}

#ground {
  position: absolute;
  background: #666;
  top: 140px;
  height: 120px;
  width: 400px;
}

html,body {
  position: relative;
  height: 100%;
  margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.14.2/matter.min.js" integrity="sha512-pi0tSRZdlNRZeANPwdAIHRAYg6gZZV6QlAiyHXn5TYqLzBKE9jlttO/QgYLMhISD6oNv2kPsVelx+n5nw0FqKA==" crossorigin="anonymous"></script>
<div id="box"></div>
<div id="ground"></div>

反应

React改变了工作流程,但基本概念是相同的-MJS主体数据从MJS后端单向流向渲染前端,因此从MJS的角度看,一切都与上面的原始示例相同。大部分工作是正确设置refsuseEffect以便与requestAnimationFrame一起使用。

#box {
  position: absolute;
  background: #111;
  height: 40px;
  width: 40px;
  cursor: move;
}

#ground {
  position: absolute;
  top: 140px;
  height: 120px;
  width: 400px;
  background: #666;
}

html,body {
  position: relative;
  height: 100%;
  margin: 0;
}
<script type="text/babel" defer>
const {Fragment,useEffect,useRef} = React;

const Scene = () => {
  const requestRef = useRef();
  const boxRef = useRef();
  const groundRef = useRef();

  const animate = () => {
    const engine = Matter.Engine.create();
    
    const box = {
      body: Matter.Bodies.rectangle(150,elem: boxRef.current,render: function () {
        const {x,y} = this.body.position;
        this.elem.style.top = `${y - 20}px`;
        this.elem.style.left = `${x - 20}px`;
        this.elem.style.transform = `rotate(${this.body.angle}rad)`;
      },};
    const ground = Matter.Bodies.rectangle(
      200,{isStatic: true}
    );
    const mouseConstraint = Matter.MouseConstraint.create(
      engine,{element: document.body}
    );
    Matter.World.add(
      engine.world,mouseConstraint]
    );
    
    (function rerender() {
      box.render();
      Matter.Engine.update(engine);
      requestRef.current = requestAnimationFrame(rerender);
    })();
  };
  
  useEffect(() => {
    animate();
    return () => cancelAnimationFrame(requestRef.current);
  },[]);
  
  return (
    <Fragment>
      <div id="box" ref={boxRef}></div>
      <div id="ground" ref={groundRef}></div>
    </Fragment>
  );
};

ReactDOM.render(<Scene />,document.body);

</script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.14.2/matter.min.js" integrity="sha512-pi0tSRZdlNRZeANPwdAIHRAYg6gZZV6QlAiyHXn5TYqLzBKE9jlttO/QgYLMhISD6oNv2kPsVelx+n5nw0FqKA==" crossorigin="anonymous"></script>

请注意,这些只是概念证明。在可以支持更多涉及的用例之前,可能有必要进行更多的工作来建立抽象。