简体   繁体   English

使用 Matter.js 渲染到 DOM 或 React

[英]Using Matter.js to render to the DOM or React

I want to render custom HTML elements as Bodies in Matter.js.我想将自定义 HTML 元素呈现为 Matter.js 中的正文。 I am using it in React which adds a bit of complexity but it's irrelevant to my issue.我在 React 中使用它会增加一些复杂性,但这与我的问题无关。

I've searched a lot and the only example I found was this one here , which seems to use querySelector to select the elements that live in the HTML code then somehow use them inside the rectangle shapes.我已经搜索了很多,我找到的唯一例子是这里的这个,它似乎使用querySelector来选择存在于 HTML 代码中的元素,然后以某种方式在矩形形状内使用它们。

The part that seems to be doing the job is the following:似乎正在做这项工作的部分如下:

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);

(the VIEW variables there could be just random numbers as they define the shape) VIEW变量在定义形状时可能只是随机数)

However, I cannot understand how to pass an HTML element inside the Bodies rectangle as in the example above.但是,我无法理解如何在 Bodies 矩形内传递 HTML 元素,如上例所示。

Ideally, I want to have complex HTML elements interacting with the physics world (like a small box with buttons, etc).理想情况下,我希望复杂的 HTML 元素与物理世界进行交互(例如带有按钮的小盒子等)。

Any ideas on how this could be achieved?关于如何实现这一目标的任何想法? Or, can you explain the method used in the example that seems to have managed it?或者,您能否解释一下示例中使用的似乎已经管理它的方法?

However, I cannot understand how to pass an HTML element inside the Bodies rectangle as in the example above.但是,我无法理解如何在 Bodies 矩形内传递 HTML 元素,如上例所示。

This isn't quite what the example does.这不是这个例子所做的。 When running headlessly, Matter.js handles the physics without having any idea how it's rendered.当无头运行时,Matter.js 处理物理而不知道它是如何渲染的。 Per animation frame, you can use the current positions of the MJS bodies and reposition your elements (or draw on canvas, etc) to reflect MJS's view of the world.每个动画帧,您可以使用 MJS 主体的当前位置并重新定位您的元素(或在画布上绘制等)以反映 MJS 的世界观。

Providing a root element to MJS does seem to break the one-way data flow, but this is only for informing MJS about events like mouse position and clicks--not to be confused with rendering.为 MJS 提供一个根元素似乎确实打破了单向数据流,但这只是为了通知 MJS 有关鼠标位置和点击等事件——不要与渲染混淆。

Here's a minimal example to hopefully make this clearer:这是一个最小的例子,希望能更清楚地说明这一点:

 const engine = Matter.Engine.create(); const box = { body: Matter.Bodies.rectangle(150, 0, 40, 40), elem: document.querySelector("#box"), render() { 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.17.1/matter.min.js"></script> <div id="box"></div> <div id="ground"></div>

React反应

React changes the workflow but the fundamental concept is the same--MJS body data flows one-directionally from the MJS back-end to the rendering front-end, so from MJS' perspective, everything is identical as the vanilla example above. React 改变了工作流程,但基本概念是相同的——MJS 主体数据从 MJS 后端单向流向渲染前端,因此从 MJS 的角度来看,一切都与上面的 vanilla 示例相同。 Most of the work is setting up refs and useEffect properly for use with requestAnimationFrame .大多数工作是正确设置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, 0, 40, 40), elem: boxRef.current, render() { 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); 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/17.0.2/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.17.1/matter.min.js"></script>

Note that these are only proofs-of-concept.请注意,这些只是概念验证。 More work setting up abstractions will likely be necessary before they can support more involved use cases.在支持更多涉及的用例之前,可能需要更多的工作来设置抽象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM