我创建了一个简单的 React 应用程序,它使用 PixiJS 并且运行良好。
无论浏览器窗口宽度如何,画布的 1:1 宽高比都是通过
ResizeObserver
保持的,如下所示:
但是,我必须在那里使用解决方法:我让
PIXI.Application
动态创建一个画布元素,然后将其分配给ReactchildRef.current
,如下所示:
const PixiGame = () => {
const parentRef = useRef(null);
const childRef = useRef(null); // as a workaround I have to assign the canvas element below, created by PIXI app
useEffect(() => {
const parentElement = parentRef.current;
const app = new Application({
backgroundColor: 0xccffcc,
width: 800,
height: 800,
});
// the PIXI app has created a canvas element - make it a child of the parent div
const childElement = app.view;
childElement.id = "child";
childElement.classList.add("child");
childRef.current = childElement;
parentElement.appendChild(childElement);
当我尝试采用更自然的方式并在其他类似应用程序的JSX中声明canvas元素时,我收到错误消息:
Error: Invalid value of `0` passed to `checkMaxIfStatementsInShader`
at checkMaxIfStatementsInShader (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:5189:11)
at _BatchRenderer2.contextChange (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:8129:27)
at Runner.emit (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:5340:22)
at ContextSystem.initFromContext (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:8619:155)
at ContextSystem.initFromOptions (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:8631:10)
at ContextSystem.init (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:8603:168)
at Runner.emit (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:5340:22)
at StartupSystem.run (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:11443:27)
at new _Renderer2 (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:13203:478)
at autoDetectRenderer (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:12931:14)
这是我尝试使用的代码,其中画布元素在 JSX 中定义:
const PixiGame = () => {
const parentRef = useRef(null);
const childRef = useRef(null);
useEffect(() => {
const parentElement = parentRef.current;
const childElement = childRef.current; // here I just use the existing canvas element, defined in JSX below
const app = new Application({
backgroundColor: 0xccffcc,
width: 800,
height: 800,
view: childElement,
});
const resizeObserver = new ResizeObserver((entries) => {
for (let entry of entries) {
const { width, height } = entry.contentRect;
const minDimension = Math.floor(Math.min(width, height));
// maintain the 1:1 aspect ratio of the child element
childElement.style.width = `${minDimension}px`;
childElement.style.height = `${minDimension}px`;
}
});
resizeObserver.observe(parentElement);
const background = new Graphics();
for (let i = 0; i < 8; i++) {
for (let j = 0; j < 8; j++) {
if ((i + j) % 2 == 0) {
background.beginFill(0xccccff);
background.drawRect(i * 100, j * 100, 100, 100);
background.endFill();
}
}
}
app.stage.addChild(background);
const texture = Texture.from("https://pixijs.com/assets/bunny.png");
const bunny = new Sprite(texture);
bunny.anchor.set(0.5);
bunny.x = 50;
bunny.y = 50;
bunny.width = 100;
bunny.height = 100;
app.stage.addChild(bunny);
return () => {
resizeObserver.unobserve(parentElement);
resizeObserver.disconnect();
parentElement.removeChild(childElement);
app.destroy(true, true);
};
}, []);
return (
<div className="verticalFlexContainer">
<div className="hint">Game No. 1 Score1:Score2</div>
<div className="parent" ref={parentRef}>
<canvas className="child" id="child" ref={childRef}></canvas>
</div>
<div className="status">A game hint to do this and that...</div>
</div>
);
};
该错误似乎与 React 生命周期或其严格模式有关......
我尝试打印
childRef.current
和 parentRef.current
,但它们永远不会为空。
有人建议如何在我的应用程序的 JSX 部分中定义画布,并且仍然能够在 Pixi 代码中使用它吗?
PS:是的,我已经尝试过CSS
aspect-ratio: 1
,但它对我来说效果不佳,这就是我使用ResizeObserver
的原因。
PPS:不,我不想使用“@pixi/react”包,因为我想以命令式(而不是声明式)风格使用 PixiJS,而且它似乎工作得足够好。
没有太多时间玩它,但它可能会有所帮助。
App.destroy() 函数被描述为从 DOM 中删除 canvas 元素,因此当你的 useEffect 运行 cleanup 时,它会从 JSX 中销毁 canvas 元素。
在第一个示例中,您在每次 useEffect 运行时创建新的画布元素,但在第二个代码片段中,它在 JSX 中创建了一次 -> 在 unmound 时被删除 -> 并且没有重新创建,从而导致错误。