使用 Matter.js 渲染到 DOM 或 React

我想在 Matter.js 中将自定义 HTML 元素呈现为主体。我在 React 中使用它,这增加了一些复杂性,但它与我的问题无关。


我搜索了很多,我找到的唯一示例是这里的这个,它似乎用于querySelector选择 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 元素与物理世界交互(比如带有按钮的小盒子等)。


关于如何实现这一目标的任何想法?或者,您能否解释一下示例中使用的似乎已经成功解决的方法?


小唯快跑啊
浏览 229回答 1
1回答

湖上湖

但是,我无法理解如何像上面的示例那样在 Bodies 矩形内传递 HTML 元素。这不是这个例子所做的。当无头运行时,Matter.js 处理物理而不知道它是如何呈现的。每个动画帧,您可以使用 MJS 主体的当前位置并重新定位您的元素(或在画布上绘制等)以反映 MJS 的世界观。向 MJS 提供根元素似乎会破坏单向数据流,但这只是为了通知 MJS 有关鼠标位置和点击等事件的信息——不要与渲染混淆。这是一个希望能使这一点更清楚的最小示例:const engine = Matter.Engine.create();&nbsp;&nbsp;const box = {&nbsp; body: Matter.Bodies.rectangle(150, 0, 40, 40),&nbsp; elem: document.querySelector("#box"),&nbsp; render() {&nbsp; &nbsp; const {x, y} = this.body.position;&nbsp; &nbsp; this.elem.style.top = `${y - 20}px`;&nbsp; &nbsp; this.elem.style.left = `${x - 20}px`;&nbsp; &nbsp; this.elem.style.transform = `rotate(${this.body.angle}rad)`;&nbsp; },};const ground = Matter.Bodies.rectangle(&nbsp; 200, 200, 400, 120, {isStatic: true});const mouseConstraint = Matter.MouseConstraint.create(&nbsp; engine, {element: document.body});Matter.Composite.add(&nbsp; engine.world, [box.body, ground, mouseConstraint]);(function rerender() {&nbsp; box.render();&nbsp; Matter.Engine.update(engine);&nbsp; requestAnimationFrame(rerender);})();#box {&nbsp; position: absolute;&nbsp; background: #111;&nbsp; height: 40px;&nbsp; width: 40px;&nbsp; cursor: move;}#ground {&nbsp; position: absolute;&nbsp; background: #666;&nbsp; top: 140px;&nbsp; height: 120px;&nbsp; width: 400px;}html, body {&nbsp; position: relative;&nbsp; height: 100%;&nbsp; margin: 0;}<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script><div id="box"></div><div id="ground"></div>反应React 改变了工作流程,但基本概念是相同的——MJS 主体数据从 MJS 后端单向流向渲染前端,因此从 MJS 的角度来看,一切都与上面的普通示例相同。大部分工作是设置refs并useEffect正确地与requestAnimationFrame.const {Fragment, useEffect, useRef} = React;const Scene = () => {&nbsp; const requestRef = useRef();&nbsp; const boxRef = useRef();&nbsp; const groundRef = useRef();&nbsp; const engineRef = useRef();&nbsp; const animate = () => {&nbsp; &nbsp; engineRef.current = Matter.Engine.create();&nbsp; &nbsp; const engine = engineRef.current;&nbsp; &nbsp; const box = {&nbsp; &nbsp; &nbsp; body: Matter.Bodies.rectangle(150, 0, 40, 40),&nbsp; &nbsp; &nbsp; elem: boxRef.current,&nbsp; &nbsp; &nbsp; render() {&nbsp; &nbsp; &nbsp; &nbsp; const {x, y} = this.body.position;&nbsp; &nbsp; &nbsp; &nbsp; this.elem.style.top = `${y - 20}px`;&nbsp; &nbsp; &nbsp; &nbsp; this.elem.style.left = `${x - 20}px`;&nbsp; &nbsp; &nbsp; &nbsp; this.elem.style.transform = `rotate(${this.body.angle}rad)`;&nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; };&nbsp; &nbsp; const ground = Matter.Bodies.rectangle(&nbsp; &nbsp; &nbsp; 200, // x&nbsp; &nbsp; &nbsp; 200, // y&nbsp; &nbsp; &nbsp; 400, // w&nbsp; &nbsp; &nbsp; 120, // h&nbsp; &nbsp; &nbsp; {isStatic: true}&nbsp; &nbsp; );&nbsp; &nbsp; const mouseConstraint = Matter.MouseConstraint.create(&nbsp; &nbsp; &nbsp; engine,&nbsp; &nbsp; &nbsp; {element: document.body}&nbsp; &nbsp; );&nbsp; &nbsp; Matter.Composite.add(engine.world, [&nbsp; &nbsp; &nbsp; box.body,&nbsp; &nbsp; &nbsp; ground,&nbsp; &nbsp; &nbsp; mouseConstraint,&nbsp; &nbsp; ]);&nbsp; &nbsp; (function rerender() {&nbsp; &nbsp; &nbsp; box.render();&nbsp; &nbsp; &nbsp; Matter.Engine.update(engine);&nbsp; &nbsp; &nbsp; requestRef.current = requestAnimationFrame(rerender);&nbsp; &nbsp; })();&nbsp; };&nbsp; useEffect(() => {&nbsp; &nbsp; animate();&nbsp; &nbsp; return () => {&nbsp; &nbsp; &nbsp; cancelAnimationFrame(requestRef.current);&nbsp; &nbsp; &nbsp; Matter.Engine.clear(engineRef.current);&nbsp; &nbsp; &nbsp; // see https://github.com/liabru/matter-js/issues/564&nbsp; &nbsp; &nbsp; // for additional cleanup if using MJS renderer/runner&nbsp; &nbsp; };&nbsp; }, []);&nbsp; return (&nbsp; &nbsp; <Fragment>&nbsp; &nbsp; &nbsp; <div id="box" ref={boxRef}></div>&nbsp; &nbsp; &nbsp; <div id="ground" ref={groundRef}></div>&nbsp; &nbsp; </Fragment>&nbsp; );};ReactDOM.createRoot(document.querySelector("#app")).render(&nbsp; <Scene />);#box {&nbsp; position: absolute;&nbsp; background: #111;&nbsp; height: 40px;&nbsp; width: 40px;&nbsp; cursor: move;}#ground {&nbsp; position: absolute;&nbsp; top: 140px;&nbsp; height: 120px;&nbsp; width: 400px;&nbsp; background: #666;}html, body {&nbsp; position: relative;&nbsp; height: 100%;&nbsp; margin: 0;}<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script><script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script><div id="app"></div>请注意,这些只是概念验证。在它们能够支持更多涉及的用例之前,可能需要更多的工作来设置抽象。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript