【问题标题】:drawImage on HTML5 canvas is not workingHTML5 画布上的 drawImage 不起作用
【发布时间】:2016-06-15 20:06:41
【问题描述】:

我正在创建一个“接住掉落物品”游戏,并已成功将“捕手”图像和“掉落物品”图像绘制到画布上。但我还想在没有捕捉到下落图像并击中我的 html5 画布底部时显示图像(x.png)。 generateX 函数是从 animate 函数中调用的,当一个下落的图像碰到画布的底部时。 sound.play() 正在工作。 generateX 函数中的 console.logs 记录以下内容 - 2,3 | 1,3 | 1,3 - 所以我知道这个函数第一次运行时图像没有完全加载。除了实际的图像显示外,一切似乎都在工作。我试图以其他线程建议的方式构造它,但没有任何效果。非常感谢任何帮助!

generateX: function() {
    console.log('inside generateX func');
    var imgX = new Image();
    imgX.src = 'assets/x.png';
    function drawX() {
        console.log(3);
        counter+=20;
        context.drawImage(imgX, xIcon.x + counter, xIcon.y, xIcon.width, xIcon.height);
        xArr.push(imgX);
        console.log('xArr', xArr);
    }
    if (imgX.complete) {
        console.log(1);
        drawX();
    } else {
        console.log(2);
        imgX.onload = drawX;
    }
        helper.checkMisses();
}

animate: function() {
    var sound;
    if (continueAnimating) {
        requestAnimationFrame(helper.animate);
    }
    for (var i = 0; i < surveys.length; i++) {
        var survey = surveys[i];
        if (helper.isColliding(survey, dinoSaurus)) {
            sound = new Audio("audio/coinSound.mp3");
            sound.play();
            score += 5;
            helper.resetSurvey(survey);
        }
        survey.y += survey.speed;
        // if the survey is below the canvas,
        if (survey.y > canvas.height) {
            sound = new Audio("audio/buzzerSound.mp3");
            sound.play();
            helper.generateX();
            helper.resetSurvey(survey);
        }
    }
    // redraw everything
    helper.drawAll();
}

--

resetSurvey: function(survey) {
    // randomly position survey near the top of canvas
    survey.x = Math.random() * (canvas.width - surveyWidth);
    survey.y = 40 + Math.random() * 30;
    survey.speed = (0.55 + Math.random()) * 0.9;
}

【问题讨论】:

  • imgX 可能需要一段时间才能加载,resetSurvey 可能会在 img 尝试显示时运行。 resetSurvey 是否正在清除画布?
  • 这是一个很好的建议 - 但 resetSurvey 不会清除画布。我已经在上面的原始帖子中发布了。
  • 启动游戏之前加载所有图片,然后启动游戏。这里是 mixin 问题(加载和绘图)。

标签: javascript html5-canvas


【解决方案1】:

尝试早点加载您的图片

如果我正确理解您的情况,我认为问题在于您需要更早地加载图像,以便在您想要绘制它时轻松准备好,而不是等待仅在 generateX 内加载它。您当前编码的方式是加载图像(imgX.src = ...),然后立即尝试绘制它。没错,您正在检查加载是否完成,如果没有,请稍后再试。但是,更好的策略是更早地加载图像,例如在游戏初始化期间。

演示

下面的代码 sn-p 演示了这样做的不同之处。它加载 2 个不同的图像。两者之间的唯一区别是一个(左侧)提前加载,另一个(右侧)仅在generateX 内部加载。前一个图像在游戏循环中第一次正确显示,而后一个图像第一次丢失,仅在第二次正确显示。

function loadLeftImageWellBeforeRunningGenerateX() { // correct timing
  imgs[0] = new Image();
  imgs[0].src = 'http://placehold.it/200x100.png';
}

function loadRightImageInsideGenerateX() { // incorrect timing
  imgs[1] = new Image();
  imgs[1].src = 'http://placehold.it/100x50.png';
}

function generateX() {
  loadRightImageInsideGenerateX();
  log('--inside generateX func');
  imgs.forEach(function(imgX, num) { // same as your original code, just done for 2 different images
    if (imgX.complete) {
      log("----image #" + num + " (" + side[num] + "); " + 1 + ", i.e. image complete");
      drawX(imgX, num);
    } else {
      log("----image #" + num + " (" + side[num] + "); " + 2 + ", i.e. image not complete");
      imgX.onload = drawX(imgX, num);
    }
  });
}

function drawX(imgX, num) { // same as your original code, just allows placement of 2 images side-by-side
  log("----image #" + num + " (" + side[num] + "); " + 3 + ", i.e. drawing image (" + prefix[num] + "successfully)");
  context.drawImage(imgX, num * 150 + 10, 10, 100, 50);
  if (num === 1) {prefix[1] = "";}
}

var
  imgs = [],
  numClicks = 0,
  side = ["left", "right"],
  prefix = ["", "un"],
  button = document.querySelector("button"),
  canvas = document.getElementById('myCanvas'),
  context = canvas.getContext('2d');
context.fillStyle = "yellow";
context.fillRect(0, 0, 300, 150);

// as far as game logic goes, the only important lines below are marked with arrows
// the rest is just "fluff" to make the demo more understandable to the user
button.addEventListener("click", function() {
  numClicks += 1;
  if (numClicks === 1) {
    log("You must clear your browser's recent cache every time you run this snippet " +
      "in order for it to demonstrate the problems and solutions " +
      "associated with loading images in this code.");
    button.innerHTML = "Clear browser cache and click here again to start game initialization";
  } else if (numClicks === 2) {
    loadLeftImageWellBeforeRunningGenerateX(); // <----- ***
    log("Game initializes. No images should yet be visible, " +
      "but image #0 (left) should be loading/loaded now, i.e. ahead of time. " +
      "Image #1 (right) is not yet loading/loaded. Click again to 'play game'.");
    button.innerHTML = "Do NOT clear the browser cache and click here again to start playing game";
  } else {
    button.innerHTML = "Do NOT clear the browser cache and click here again to continue playing game";
    if (numClicks === 3) {
      log("Game begins. Images are required for the first time. Only the pre-loaded left image shows " +
        "even though loading both is attempted.");
    } else {
      log("Game continues. On second and subsequent re-draws, both images are now available and visible.");
    }
    generateX(); // <----- ***
  }
});

function log(msg) {
  document.body.appendChild(document.createElement("p")).innerHTML = msg;
}
p {
  margin: 0.2em;
}
<canvas id="myCanvas" width="300" height="80"></canvas>
<div>
  <button>Click here to begin demo</button>
</div>

您的浏览器缓存可以隐藏此错误

顺便说一句,如果当您尝试调试此类事情时,请注意许多/大多数/所有浏览器会缓存图像,如果您不知道发生了什么,则可能难以复制此类错误在。例如,您可能会运行有错误的代码,并且在游戏周期的第一次时图像丢失。您研究您的代码,进行更改以尝试修复错误并再次运行代码。瞧,看起来问题已解决,因为图像现在第一次出现在游戏周期中。然而,事实上,它可能只在第一个循环中出现,不是因为错误已修复,而是因为浏览器即使在第一个游戏循环中也能够使用缓存的图像,从而无需从源加载它。简而言之,如果您尝试调试这样的问题,您怀疑文件加载的时间很重要,但错误只是有时会出现,请尝试清除浏览器的最近缓存以查看是否使错误更加明显。

清除浏览器的缓存:

  • Firefox(适用于 Mac 或 Windows,v44...):单击“历史记录”/单击“清除最近的历史记录...”/如有必要,单击打开“详细信息”/选中“缓存”/单击“立即清除”
  • Chrome(适用于 Mac,v48...)“Chrome”(左侧菜单项)/“清除浏览数据...”/选择“缓存的图像和文件”/单击“清除浏览数据”
  • Chrome(适用于 Windows,v48...)单击自定义和控制图标(右侧)/单击“更多工具...”/单击“清除浏览数据...”/单击“清除浏览数据"
  • Internet Explorer(适用于 Windows,v11...)单击“工具”/单击“删除浏览历史记录”/选择“下载历史记录”/单击“删除”

【讨论】:

  • 太棒了,我会试一试!感谢您的建议!
  • 太棒了!如果您认为我的回答回答了您的问题,请通过单击答案旁边的复选标记来表明这一点。这有助于。 (More info here 如果你想要的话。)谢谢。
猜你喜欢
  • 2020-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-05
  • 1970-01-01
  • 2013-05-06
  • 2013-09-01
相关资源
最近更新 更多