我正在创建一个“捕捉掉落物品”游戏,并且已经成功地将“捕捉”图像和“掉落物品”图像绘制到了画布上。但我也想在未捕获到掉落的图像并击中html5画布的底部时显示图像(x.png)。当动画图像下降到画布的底部时,从动画函数调用generateX函数。 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;
}
最佳答案
尝试更早加载图像
如果我正确理解了您的情况,我认为问题在于您需要更早加载图像,以便在要绘制图像时可以轻松地准备好图像,而不是仅在generateX
内部加载图像。当前编码的方式是,加载图像(imgX.src = ...
),然后立即尝试绘制它。是的,您正在检查加载是否完成,如果没有完成,请稍后再试。但是,更好的策略是更早地加载图像,例如在游戏初始化期间。
演示版
下面的代码片段演示了这样做的区别。它加载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 ...)单击“工具” /单击“删除浏览历史记录” /选择“下载历史记录” /单击“删除”