我用 Matter.js 构建了一个 React 网站。我正在使用
useEffect
钩子通过 Matter.js 将内容渲染到画布上(我在here找到了大部分代码)。但是,当我尝试在画布上绘制其他任何内容时,什么也没有出现。与 Matter.js 相关的所有内容都有效。
const scene = useRef()
const isDragging = useRef(false)
const engine = useRef(Engine.create())
useEffect(() => {
const cw = 1100;
const ch = 700;
const render = Render.create({
canvas: scene.current,
engine: engine.current,
options: {
width: cw,
height: ch,
wireframes: false,
background: 'transparent'
}
})
console.log("gravity " + engine.current.gravity.y + "x : " + engine.current.gravity.x)
let mouse = Mouse.create(render.canvas);
let mouseConstraint = MouseConstraint.create(engine.current, {
mouse: mouse,
constraint: {
render: {
visible: false
}
}
})
render.mouse = mouse;
World.add(engine.current.world, [
Bodies.rectangle(cw / 2, 0, cw, 20, {
isStatic: true,
density: 1
}),
Bodies.rectangle(cw / 2, ch, cw, 20, {
isStatic: true,
density: 1
}),
Bodies.rectangle(0, ch / 2, 20, ch, {
isStatic: true,
density: 1
}),
Bodies.rectangle(cw, ch / 2, 20, ch, {
isStatic: true,
density: 1
}),
mouseConstraint,
])
Runner.run(engine.current)
Render.run(render)
Events.on(mouseConstraint, "mousedown", function(event) {
handleSelections(mouseConstraint.body)
})
Events.on(mouseConstraint, "startdrag", function(event) {
isDragging.current = true
})
Events.on(mouseConstraint, "enddrag", function() {
isDragging.current = false
})
Events.on(engine.current, 'afterUpdate', function() {
countTen.current = countTen.current + 1;
if (countTen.current == 10) {
countTen.current = 0;
if (selectedObjectRef.current != null) {
setGraphingPos(selectedObjectRef.current.velocity.y * -1);
setTicks(ticks + 1)
}
}
})
// ******************* This part doesn't work **************************
scene.current.getContext('2d').beginPath();
scene.current.getContext('2d').arc(100, 100, 20, 0, 2 * Math.PI, false);
scene.current.getContext('2d').fillStyle = 'red';
scene.current.getContext('2d').fill();
// **********************************************************************
return () => {
Render.stop(render)
World.clear(engine.current.world)
Engine.clear(engine.current)
render.canvas.remove()
render.canvas = null
render.context = null
render.textures = {}
}
}, [])
<canvas ref={scene} onClick={ handleMouseDown} className='main-canvas'></canvas>
非常感谢任何形式的帮助!
目前,您正在预先在 MJS 每帧擦拭的同一画布上绘制一次。因此,您绘制圆圈,然后 MJS 在渲染第一帧时立即擦除画布。当引擎和渲染器继续运行时,您永远不会尝试再次绘制。
我看到了一些解决方案(至少!)。哪个最合适取决于您的具体用例。
afterRender
回调内的每个帧上为
render
对象绘制。这是您现在所处的最简单、最直接的解决方案,我在下面提供了一个示例。
useEffect
没有任何关系;即使您在 vanilla JS 中注入普通画布,也会出现同样的问题。另外,请记住,无论你画什么,除了恰好在同一个画布上之外,都与 MJS 完全无关。不要指望物理学会对其起作用,除非您使用 MJS 知道的物体坐标。
虽然您尚未提供完整的组件,但这是上述
afterRender
方法的最小概念验证:
const {useEffect, useRef} = React;
const {Bodies, Engine, Events, Render, Runner, Composite} = Matter;
const Scene = () => {
const canvasRef = useRef();
useEffect(() => {
const cw = 200;
const ch = 200;
const engine = Engine.create();
const ctx = canvasRef.current.getContext("2d");
const render = Render.create({
canvas: canvasRef.current,
engine,
options: {
width: cw,
height: ch,
wireframes: false,
background: "transparent",
}
});
const handleAfterRender = () => {
const x = Math.cos(Date.now() / 300) * 80 + 100;
const y = Math.sin(Date.now() / 299) * 80 + 100;
ctx.beginPath();
ctx.arc(x, y, 20, 0, 2 * Math.PI);
ctx.fillStyle = "red";
ctx.fill();
};
Events.on(render, "afterRender", handleAfterRender);
Composite.add(engine.world, [
Bodies.rectangle(cw / 2, 0, cw, 20, {
isStatic: true,
density: 1,
}),
Bodies.rectangle(cw / 2, ch, cw, 20, {
isStatic: true,
density: 1,
}),
Bodies.rectangle(0, ch / 2, 20, ch, {
isStatic: true,
density: 1,
}),
Bodies.rectangle(cw, ch / 2, 20, ch, {
isStatic: true,
density: 1,
}),
]);
Runner.run(engine);
Render.run(render);
return () => {
Events.off("afterRender", handleAfterRender);
Render.stop(render);
Composite.clear(engine.world);
Engine.clear(engine);
render.canvas.remove();
render.canvas = null;
render.context = null;
render.textures = {};
};
}, []);
return <canvas ref={canvasRef}></canvas>;
};
const root = document.querySelector("#app");
ReactDOM.createRoot(root).render(<Scene />);
<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.20.0/matter.min.js"></script>
<div id="app"></div>