在渲染 JS 之前加载图像 canvas
Loading images before rendering JS canvas
我正在编写一个简单的游戏来学习 JS,我正在学习 HTML5,所以我需要在 canvas 上画东西。
代码如下:
let paddle = new Paddle(GAME_WIDTH,GAME_HEIGHT);
new InputHandler(paddle);
let lastTime = 0;
const ball = new Image();
ball.src = 'assets/ball.png';
function gameLoop(timeStamp){
let dt = timeStamp - lastTime;
lastTime = timeStamp;
ctx.clearRect(0,0,600,600);
paddle.update(dt);
paddle.draw(ctx);
ball.onload = () => {
ctx.drawImage(ball,20,20);
}
window.requestAnimationFrame(gameLoop);
}
gameLoop();
截图:没有球
before comment
现在我注释掉 clearRect()
:
after comment
你好球。
canvas底部还有一个桨,似乎不受clearRect()
方法的影响。它工作得很好。我在这里错过了什么?
将图像的 onload
处理程序放在游戏循环中没有多大意义。这意味着游戏必须在设置图像的 onload
功能之前 运行 开始,从而导致相当混乱的情况。
正确的顺序是设置 onload
处理程序,然后是图像源,然后 await
所有图像 onload
在 运行 游戏循环之前触发.当你只有一张图片时,直接将主循环设置为 onload
非常容易,但对于具有多个资产的游戏,这很快就会变得尴尬。
这是一个简单的示例,说明您可以如何使用 Promise.all
加载许多游戏资产。您很可能希望将加载的图像解压缩为更具描述性的对象而不是数组,但这是一个开始。
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
canvas.width = 400;
canvas.height = 250;
const ctx = canvas.getContext("2d");
const assets = [
"http://placekitten.com/120/100",
"http://placekitten.com/120/120",
"http://placekitten.com/120/140",
];
const assetsLoaded = assets.map(url =>
new Promise(resolve => {
const img = new Image();
img.onerror = e => reject(`${url} failed to load`);
img.onload = e => resolve(img);
img.src = url;
})
);
Promise
.all(assetsLoaded)
.then(images => {
(function gameLoop() {
requestAnimationFrame(gameLoop);
ctx.clearRect(0, 0, canvas.width, canvas.height);
images.forEach((e, i) =>
ctx.drawImage(
e,
i * 120, // x
Math.sin(Date.now() * 0.005) * 20 + 40 // y
)
);
})();
})
.catch(err => console.error(err))
;
我正在编写一个简单的游戏来学习 JS,我正在学习 HTML5,所以我需要在 canvas 上画东西。
代码如下:
let paddle = new Paddle(GAME_WIDTH,GAME_HEIGHT);
new InputHandler(paddle);
let lastTime = 0;
const ball = new Image();
ball.src = 'assets/ball.png';
function gameLoop(timeStamp){
let dt = timeStamp - lastTime;
lastTime = timeStamp;
ctx.clearRect(0,0,600,600);
paddle.update(dt);
paddle.draw(ctx);
ball.onload = () => {
ctx.drawImage(ball,20,20);
}
window.requestAnimationFrame(gameLoop);
}
gameLoop();
截图:没有球 before comment
现在我注释掉 clearRect()
:
after comment
你好球。
canvas底部还有一个桨,似乎不受clearRect()
方法的影响。它工作得很好。我在这里错过了什么?
将图像的 onload
处理程序放在游戏循环中没有多大意义。这意味着游戏必须在设置图像的 onload
功能之前 运行 开始,从而导致相当混乱的情况。
正确的顺序是设置 onload
处理程序,然后是图像源,然后 await
所有图像 onload
在 运行 游戏循环之前触发.当你只有一张图片时,直接将主循环设置为 onload
非常容易,但对于具有多个资产的游戏,这很快就会变得尴尬。
这是一个简单的示例,说明您可以如何使用 Promise.all
加载许多游戏资产。您很可能希望将加载的图像解压缩为更具描述性的对象而不是数组,但这是一个开始。
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
canvas.width = 400;
canvas.height = 250;
const ctx = canvas.getContext("2d");
const assets = [
"http://placekitten.com/120/100",
"http://placekitten.com/120/120",
"http://placekitten.com/120/140",
];
const assetsLoaded = assets.map(url =>
new Promise(resolve => {
const img = new Image();
img.onerror = e => reject(`${url} failed to load`);
img.onload = e => resolve(img);
img.src = url;
})
);
Promise
.all(assetsLoaded)
.then(images => {
(function gameLoop() {
requestAnimationFrame(gameLoop);
ctx.clearRect(0, 0, canvas.width, canvas.height);
images.forEach((e, i) =>
ctx.drawImage(
e,
i * 120, // x
Math.sin(Date.now() * 0.005) * 20 + 40 // y
)
);
})();
})
.catch(err => console.error(err))
;