【问题标题】:HTML5/Javascript Image loading method & passing to variableHTML5/Javascript 图像加载方法 & 传递给变量
【发布时间】:2016-02-13 14:42:27
【问题描述】:

我有一些加载图片的代码。

var assets = {
    total:0,
    success:0,
    error:0
};
var stillLoading = true;
var img = {};

function LoadImage(name, path){
    var toLoad = new Image();
    toLoad.src = path;
    assets.total++;
    toLoad.addEventListener("load", function(){
        assets.success++;
        console.log(name + " loaded.");
        img[name] = toLoad;
    }, false);
    toLoad.addEventListener("error", function(){
        assets.error++;
    }, false);
};

function Loading(){
    if (assets.success == assets.total){
        if (stillLoading){
            console.log("All assets loaded. Starting game.");
        };
        stillLoading = false;
        return false;
    }else{  
        stillLoading = true;
        return true;
    };
};

可能仍然是低效和丑陋的,因为我是新手练习 javascript,欢迎提出建议。它加载图像并通过函数 Loading() 告诉主程序所有资源何时完成加载,然后将图像添加到对象 img。

我已经为我的图像使用了一段时间了,它确实有效。

例如,如果我这样做了。

LoadImage("Car", "imageOfCar.png");
ctx.drawImage(img.Car, 0, 0);

这会将图像很好地绘制到画布上。

但是,当我为另一个变量分配图像时,出于各种原因,我想要这样做,例如将图像分配给对象。例如

var secondCar = img.Car

然后尝试绘制它。

ctx.drawImage(secondCar, 0, 0);

我收到此错误。

未捕获的类型错误:无法在“CanvasRenderingContext2D”上执行“drawImage”:提供的值不是类型“(HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap)”

如果它适用于初始变量,它应该以相同的方式处理刚刚分配了完全相同的东西的另一个变量。那么为什么会出现这个错误呢?

如果我以不检查是否已完成加载的典型方式加载图像。

img.Car = new Image();
img.Car.src = "imageOfCar.png";
secondCar = img.Car;
ctx.drawImage(secondCar);

这会奏效。 这里的行为有点令人困惑,有人可以向我解释发生了什么,并可能提出解决方法吗?

编辑:只是为了澄清。

这是 html 文件,名为 index.html。

<!DOCTYPE html>
<head>
    <title>HTML5 Game Base</title>
    <link rel = "stylesheet" type = "text/css" href = "styles.css">
</head>
<body>
    <canvas id="screen" width="270" height="480" style="border:1px solid #000000;"></canvas>
    <script src = "script.js"></script>
</body>
</html>

画布设置为screen。我上面显示的所有 javascript 代码都发生在 index.html 中调用的 script.js 中。

这就是在 script.js 中调用 screen 的方式。

var canvas = document.getElementById("screen");
var ctx = canvas.getContext("2d");

这就是ctx.drawImage() 所引用的内容。

【问题讨论】:

  • ctx 变量在哪里定义?
  • 啊,那是我忘记澄清的事情了。我已经在一个 html 文件中设置了画布。 html 文件然后调用一个 javascript 文件,该文件将画布称为ctx。我在这里显示的所有代码都发生在 javascript 文件中,我已经提出了一些含义,所以如果还有什么,请询问。
  • html文件然后调用一个javascript文件,该文件将canvas调用为ctx。所以显示相关代码。
  • 完成了,请再看看。谢谢。
  • "但是,当我为另一个变量分配图像时,出于各种原因我想做的事情,例如将图像分配给对象。例如var secondCar = img.Car" 是@987654335在LoadImage 之后定义的@ 被调用?你能创建一个 stacksn-ps 或 jsfiddle jsfiddle.net 来演示错误信息吗?

标签: javascript html image load


【解决方案1】:

我知道这不是最有帮助的答案,但我稍微修改了您的代码。这是我用的:

<!DOCTYPE html>
<head>
    <title>HTML5 Game Base</title>
</head>
<body>
    <canvas id="screen" width="270" height="480" style="border:1px solid #000000;"></canvas>
    <script>
    var stillLoading = true;
    var img = {};
    var canvas = document.getElementById("screen");
    var ctx = canvas.getContext("2d");
    assets = {};
    assets.total = 0;

    function LoadImage(name, path){
        var toLoad = new Image();
        toLoad.src = path;
        assets.total++;
        toLoad.addEventListener("load", function(){
            //assets.success++;
            console.log(name + " loaded.");
            img[name] = toLoad;
        }, false);
        toLoad.addEventListener("error", function(){
            assets.error++;
        }, false);
    }

    </script>
</body>
</html>

然后我在 Chrome 的控制台中输入

LoadImage("Car", "map.png");
LoadImage("un", "Untitled.png");
ctx.drawImage(img.Car, 0, 0);
ctx.drawImage(img.un, 0, 0);

并获得在画布中加载图像的预期结果。即使将img 图像之一分配给新变量,这也可以按预期工作。

var second = img.Car
ctx.drawImage(second, 0, 0)

手动运行时似乎一切正常,所以我的猜测是时间。你什么时候运行这些命令?它们是在 js 文件中还是来自控制台?

看来您的 LoadImage 函数没问题。抱歉,这不是很有帮助,但希望能帮助您排除不去寻找问题的地方。

【讨论】:

  • 我在 js 文件中运行它们。我正在使用我的 Loading() 函数来确保任何将使用资产的代码只会在所有图像加载后运行,看来你已经摆脱了它。
  • 我这样做是因为我只是从控制台运行它。绝对听起来像一个时间问题。基本上,当您尝试加载图像时,图像还没有准备好。这是 JS 的常见痛点之一。我下面的答案谈到了承诺,这就是要走的路。一开始他们可能很难理解,但值得一试。
【解决方案2】:

一种方法可以是利用 Promise ,因为 new Imageload 事件是异步的 secondCar 在用作 setInterval 中的参数时可以是 undefined,例如,@987654328 的 load 事件在调用LoadImage 后应用var secondCar = img.Car 时,@ 可能不完整;还为setInterval 添加了变量引用,以便在需要时调用clearInterval()

var canvas = document.getElementById("screen");
var ctx = canvas.getContext("2d");

var interval = null;

var assets = {
  total: 0,
  success: 0,
  error: 0
};
var stillLoading = true;
var img = {};

function LoadImage(name, path) {
  return new Promise(function(resolve, reject) {
    var toLoad = new Image();
    assets.total++;
    toLoad.addEventListener("load", function() {
      assets.success++;
      console.log(name + " loaded.");
      img[name] = toLoad;
      // resolve `img` , `assets` object
      resolve([img, assets])
    }, false);
    toLoad.addEventListener("error", function() {
      assets.error++;
      reject(assets)
    }, false);
    toLoad.src = path;
  })
};

function Loading() {
  if (assets.success == assets.total) {
    if (stillLoading) {
      console.log("All assets loaded. Starting game.");
    };
    stillLoading = false;
    return false;
  } else {
    stillLoading = true;
    return true;
  };
};

var promise = LoadImage("Car", "http://pngimg.com/upload/audi_PNG1736.png");
promise.then(function(data) {
  // `data` : array containing `img` , `assets` objects
  console.log(data);
  var secondCar = data[0].Car;
  interval = setInterval(function() {
    if (!(Loading())) {
      ctx.drawImage(secondCar, 0, 0);
    };
  }, 1000 / 60);
});
&lt;canvas id="screen" width="1000" height="700" style="border:1px solid #000000;"&gt;&lt;/canvas&gt;

【讨论】:

    【解决方案3】:

    解决了。原来这是一个时间问题。在我给出的示例中,当secondCar 被分配img.Car 时,img.Car 尚未加载。

    相反,我创建了一个名为Initialise() 的新函数,并从Loading() 中调用它。所以从现在开始,我只需要初始化所有可能需要来自Initialise() 的图像的变量。这样,变量只能在加载后被分配图像。

    新代码:

    var canvas = document.getElementById("screen");
    var ctx = canvas.getContext("2d");
    
    var assets = {
        total:0,
        success:0,
        error:0
    };
    var stillLoading = true;
    var img = {};
    
    function LoadImage(name, path){
        var toLoad = new Image();
        toLoad.src = path;
        assets.total++;
        toLoad.addEventListener("load", function(){
            assets.success++;
            console.log(name + " loaded.");
            img[name] = toLoad;
        }, false);
        toLoad.addEventListener("error", function(){
            assets.error++;
        }, false);
    };
    
    function Loading(){
        if (assets.success == assets.total){
            if (stillLoading){
                console.log("All assets loaded. Starting game.");
                Initialise();
            };
            stillLoading = false;
            return false;
        }else{  
            stillLoading = true;
            return true;
        };
    };
    
    LoadImage("Car", "http://pngimg.com/upload/audi_PNG1736.png");
    
    function Initialise(){
        window.secondCar = img.Car;
    };
    
    
    
    setInterval(function(){
        if (!(Loading())) ctx.drawImage(secondCar, 0, 0);
    }, 1000/60);
    

    现在可以工作了,尽管我最终自己解决了,但感谢您的帮助。我仍然会很感激有关如何改进它的任何提示。或者知道我是 javascript 新手,任何可以帮助我遵守 javascript 约定的挑剔。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-20
      • 2016-03-26
      • 1970-01-01
      • 2016-01-01
      • 2012-02-09
      相关资源
      最近更新 更多