HTML5画布图像未使用drawImage()加载 [英] HTML5 canvas images are not loading using drawImage()

查看:55
本文介绍了HTML5画布图像未使用drawImage()加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在关注freeCodeCamp编写的关于飞禽游戏的教程 https://www.youtube.com/watch?v=pufKO5EG8nc

I'm following a tutorial on a flappy bird game by freeCodeCamp https://www.youtube.com/watch?v=pufKO5EG8nc

但是我正在使用一堂课来学习更多有关它的信息.

But I'm doing it using a class to learn more about it.

问题在于,图像无法加载,而在视频中可以加载.

The problem is, the images do not load, while in the video they load fine.

我到处搜索并了解了onload事件,在该事件中实现了该事件,但仍然没有受到影响,并且在控制台中也没有错误消息.

I googled around and learned of the onload event, implemented it in there, but still no bite, and no error messages in the console.

即使没有onload事件,为什么也要加载视频图像,而我的图像却不能加载?>:(

Even without the onload events, why does the video's images load, but mine don't? >:(

我的HTML代码:

<canvas id="canvas" width="512" height="512">
</canvas>

我的JS代码:

const canvas = document.querySelector("#canvas");
class Game {
    constructor(c) {
        this.c = c; //canvas
        this.ctx = c.getContext("2d"); // context
        this.sprites = 5;
        this.loadedSprites = 0;

        this.player = new Image(); // define images
        this.bg = new Image();
        this.fg = new Image();
        this.north = new Image();
        this.south = new Image();

        this.pX = 10; // player starting location
        this.pY = 150;

        // set sprite locations and load.
        this.player.src = "images/crab.png";
        this.player.onload = this.draw;
        this.bg.src = "images/bg.png";
        this.bg.onload = this.draw;
        this.fg.src = "images/fg.png";
        this.fg.onload = this.draw;
        this.north.src = "images/obstacle.png";
        this.gap = 80;
        this.constant = this.north.height + this.gap;
        this.north.onload = this.draw;
        this.south.src = "images/obstacle.png";
        this.south.onload = this.draw;
    }

    //draw images
    draw() {
        this.loadedSprites += 1;
        if (this.loadedSprites >= this.sprites) {
            this.ctx.drawImage(this.bg, 0, 0);
            this.ctx.drawImage(this.north, 100, 0);
            this.ctx.drawImage(this.south, 0, 0 + this.constant);
            this.ctx.drawImage(this.fg, 0, this.c.height - this.fg.height);
            this.ctx.drawImage(this.player, this.pX, this.pY);
        }
    }
}
let game = new Game(canvas);

推荐答案

您的问题与作用域有关-涉及变量,对象和函数的可访问性-关键字,具体取决于实际范围.

Your problem has to do with the scope - which refers to the accessibility of variables, objects and functions - and the meaning of the this keyword depending on the actual scope.

为了更好地理解,让我们看下面的示例:

To get a better understanding let's have a look at the following example:

class Game {
  constructor() {
    console.log("Game constructor:", this);
    this.player = new Image();
    this.player.onload = this.draw;
    this.player.src = "https://picsum.photos/200/300";
  }

  draw() {
    console.log("draw:", this);
  }
}
let game = new Game();

如果您单击运行代码段",则应该在控制台中看到以下输出:

If you click 'Run code snippet', you should see the following output in the console:


Game constructor: {}
draw: <img src="https://picsum.photos/200/300"></img>

如您所见,在 draw()中调用 this 不再指的是同一件事.在第一种情况下,它是Game的对象实例(用大括号括起来),在第二种情况下,它是HTMLImageElement的实例.

As you can see a call to this inside draw() does not refer to the same thing anymore. In the first case it's an object instance of Game (hinted by the curly brackets) and in the second case it's an instance of a HTMLImageElement.

因此,您的代码仅因以下原因而失败:

So your code simply fails because:

this.loadedSprites += 1;
if (this.loadedSprites >= this.sprites) {

不引用Game类的私有变量 loadedSprites sprites -实际上,它根本不引用任何内容,因为它在绘制范围内只是未定义因此, loadedSprites 函数永远不会递增.

don't reference the Game class's private variables loadedSprites and sprites - in fact it doesn't refer anything at all as it's simply undefined within the scope of the draw function thus loadedSprites doesn't ever get incremented.

一种解决方法是使用新属性(例如)将Game类的上下文传递给每个Image实例. .reference .

One workaround is passing the context of the Game class to each Image instance using a new property e.g. .reference.

this.player = new Image();
this.player.reference = this;
this.player.onload = this.draw;

并在draw()中使用它,如:

and use it inside draw() like:

draw() {
     this.reference.loadedSprites += 1;
}

这是一个基于您的代码的完整示例:

Here's a complete example based on your code:

const canvas = document.querySelector("#canvas");
class Game {
  constructor(c) {
    this.c = c; //canvas
    this.ctx = c.getContext("2d"); // context
    this.sprites = 5;
    this.loadedSprites = 0;

    this.player = new Image(); // define images
    this.player.reference = this;
    this.bg = new Image();
    this.bg.reference = this;
    this.fg = new Image();
    this.fg.reference = this;
    this.north = new Image();
    this.north.reference = this;
    this.south = new Image();
    this.south.reference = this;

    this.pX = 10; // player starting location
    this.pY = 150;

    // set sprite locations and load.

    this.player.onload = this.draw;
    this.player.src = "https://picsum.photos/id/237/20/20";

    this.bg.onload = this.draw;
    this.bg.src = "https://picsum.photos/id/22/20/20";

    this.fg.onload = this.draw;
    this.fg.src = "https://picsum.photos/id/30/20/20";

    this.gap = 80;
    this.constant = this.north.height + this.gap;

    this.north.onload = this.draw;
    this.north.src = "https://picsum.photos/id/37/20/20";

    this.south.onload = this.draw;
    this.south.src = "https://picsum.photos/id/137/20/20";
  }

  //draw images
  draw() {
    let ref = this.reference;
    ref.loadedSprites += 1;
    if (ref.loadedSprites >= ref.sprites) {
      ref.ctx.drawImage(ref.bg, 0, 0);
      ref.ctx.drawImage(ref.north, 100, 0);
      ref.ctx.drawImage(ref.south, 0, 0 + ref.constant);
      ref.ctx.drawImage(ref.fg, 0, ref.c.height - ref.fg.height);
      ref.ctx.drawImage(ref.player, ref.pX, ref.pY);
    }
  }
}
let game = new Game(canvas);

<canvas id="canvas" width="512" height="512">
</canvas>

这篇关于HTML5画布图像未使用drawImage()加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆