我目前正在为自己制作一个 HTMLCanvas2D 引擎,但正如标题所示,画布偶尔会显示未完成的框架。何时或多久这样做并没有一致性。我认为问题是与我的结构以及反应更新组件的方式相结合的。 (如果这很重要的话,树中这些函数下面的几乎所有内容都是基于类的,而不是像反应开销那样起作用)
export function GameScreen( ... ) {
const Canvasref = useRef<HTMLCanvasElement>(null);
const Globalvars = UseGameContext(); //Get React information from outside.
const Gameinput: InputHandler = InputHandler.getInput(); //deals with Event Listeners
const Logic: GameLogic = new GameLogic(); //Entry point into my actual logic.
useEffect(() => {
function game() {
RenderLoop(
({ canvvas, ctx }) => {
... checks for a valid canvas ...
... add Event listeners ...
window.addEventListener("resize", () => { canvas.height = window.innerHeight;
canvas.width = window.innerWidth; });
//Window listener to make the canvas always the size of the Webpage if that matters here
Logic.Initialize(ctx);
},
(delta, { canvas, ctx }) => {
...Savety checks...
Logic.updateLogic(delta);
Logic.drawFrame(delta);
}, id = "myCanvas";
);
}
game();
}, []);
return (< canvas id="myCanvas" ref={Canvasref}></canvas>);
}
//the function implemented above
export function RenderLoop(
onInit: (context: {
ctx: CanvasRenderingContext2D;
canvas: HTMLCanvasElement;
}) => void,
onUpdate: (
delta: number,
context: {
ctx: CanvasRenderingContext2D;
canvas: HTMLCanvasElement;
}
) => void,
id = "myCanvas"
) {
const canvas = document.getElementById(id);
if (canvas && canvas instanceof HTMLCanvasElement) {
const ctx = canvas.getContext("2d");
if (ctx) {
onInit({ canvas, ctx });
window.requestAnimationFrame(
Update((delta) => onUpdate(delta, { canvas, ctx }))
);
}
}
}
//delta calculation and the recursive loop to rerender every frame
const Update = (onUpdate: (delta: number) => void) => (time: number) => {
if (elapsedTime !== null) {
const delta = time - elapsedTime;
onUpdate(delta);
}
elapsedTime = time;
window.requestAnimationFrame(Update(onUpdate));
};
class GameLogic {
...lots of things ...
drawFrame(delta: number) {
this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.width);
this.GameObject.forEach((object) => { object.Draw(delta)});//What I draw should not matter
}
我尝试删除clearRect,假设这可能是原因,但虽然不太明显,但它仍然发生在彼此相邻的代码行中绘制的对象之间。据我所知,逻辑和函数在每一帧中被调用,这纯粹是视觉上的。画布/窗口的大小和对象的数量似乎都没有任何明显的相关性(我现在有 1 个对象还是 20 个对象)。
如果还有其他可能对此很重要的事情,请告诉我我的代码库总体来说有点太大,无法发布所有内容,但这应该给出应该重现问题的最小值的概述
由于一个不相关的错误,我偶然发现了真正的原因。
HTMLImages 是异步加载的。我已经在前面的drawFrame函数中加载了每一帧。只需在创建对象时加载 HTMLImageElement 并仅绘制它。所以最初的帖子没有显示实际的问题原因。如果有人有类似的问题,这里是我在结构中修复它的原因:
之前:
export class Button extends GameComponent{
...
drawFrame(delta: number) {
const buttonImg = new Image();
buttonImg.src = myImportedSource;
this.ctx.drawImage(buttonImg, 0, 0, 50, 50);
}
}
之后:
export class Button extends GameComponent{
...
buttonImg: HTMLImageElement;
constructor() {
super();
const this.buttonImg = new Image();
this.buttonImg.src = myImportedSource;
}
drawFrame(delta: number) {
this.ctx.drawImage(this.buttonImg, 0, 0, 50, 50);
}
}
虽然我设法解决了自己的问题,但我希望它可以帮助任何遇到同样错误的人。或者,我可以使用await作为解决方案,但是如果某人的互联网连接不好并将fps与您的ping联系起来,这会使引擎滞后。