【问题标题】:Loading images before rendering JS canvas在渲染 JS 画布之前加载图像
【发布时间】:2020-08-03 19:17:21
【问题描述】:

我正在编写一个简单的游戏来学习 JS,并且我正在学习 HTML5,所以我需要在画布上绘制东西。

代码如下:

 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

你好球。

画布底部还有一个桨,似乎不受clearRect() 方法的影响。它工作得很好。我在这里错过了什么?

【问题讨论】:

  • “我错过了什么?”至少有一个 } 开头。此外,如果您的缩进是正确的,这将有助于阅读您的代码。 gameLoop 永远不会被调用。根据前两点,如果ball.onload 确实在gameLoop 内部,它可能永远不会触发,因为它是一个事件侦听器,并且只会触发一次;你最好有ball.onload = galeLoop;
  • @Kaiido 我已经包含了其余的代码。感谢您花时间研究这个问题。我会研究事件监听器

标签: javascript html canvas drawimage


【解决方案1】:

将图像的onload 处理程序放在游戏循环中没有多大意义。这意味着游戏必须在图像的onload 函数设置之前开始运行,这会导致相当混乱的情况。

正确的顺序是设置onload 处理程序,然后是图像源,然后await 所有图像onloads 在运行游戏循环之前触发。当您只有一张图片时,直接将主循环设置为 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 事件的窍门。它会变得相当混乱
  • 是的,promise 和 callbacks 有一个学习曲线。坚持下去。
猜你喜欢
  • 2019-01-03
  • 2021-06-30
  • 2018-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-01
  • 1970-01-01
  • 2013-02-18
相关资源
最近更新 更多