这是关于瓦片地图(64x64像素PNG)的创建。
出于演示目的,我简化了我的代码并将网格缩小为3x3字段。
问题基本上是我绘制网格时图像仍在加载,因此画布不会在第一次加载时显示。然而,在刷新时,网格加载正常,因为现在缓存了所有图像文件。
<body>
<canvas id="canvas" width="200px" height="200px"></canvas>
<script>
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
// 3X3 GRID
var mapArray=[
["tile1","tile3","tile1"],
["tile1","tile1","tile2"],
["tile3","tile1","tile2"]
];
var tile1 = new Image();
var tile2 = new Image();
var tile3 = new Image();
tile1.src='../images/test/tile1.png';
tile2.src='../images/test/tile2.png';
tile3.src='../images/test/tile3.png';
var posX=0;
var posY=0;
for(var i=0; i < mapArray.length; i++) {
for(var j=0; j < mapArray[i].length; j++) {
switch(mapArray[i][j]) {
case "tile1":
context.drawImage(tile1, posX, posY, 64, 64);
break;
case "tile2":
context.drawImage(tile2, posX, posY, 64, 64);
break;
case "tile3":
context.drawImage(tile3, posX, posY, 64, 64);
break;
}
posX+=64;
}
posX=0;
posY+=64;
}
</script>
</body>
可以找到类似的问题:
Canvas image not displaying until second attempt
Why do my canvases only load on refresh?
在这种情况下,虽然我试图生成的不仅仅是一个图像,而是一个图像网格,我尝试解决这个问题似乎遇到问题,因为没有任何负载:
<body>
<canvas id="canvas" width="200px" height="200px"></canvas>
<script>
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
// 3X3 GRID
var mapArray=[
["tile1","tile3","tile1"],
["tile1","tile1","tile2"],
["tile3","tile1","tile2"]
];
var tile1 = new Image();
var tile2 = new Image();
var tile3 = new Image();
var posX=0;
var posY=0;
for(var i=0; i < mapArray.length; i++) {
for(var j=0; j < mapArray[i].length; j++) {
switch(mapArray[i][j]) {
case "tile1":
//use onload so drawing waits until image file is loaded
tile1.onload = function() {
//draw image
context.drawImage(tile1, posX, posY, 64, 64);
};
//load image file
tile1.src='../images/test/tile1.png';
break;
case "tile2":
tile2.onload = function() {
context.drawImage(tile2, posX, posY, 64, 64);
};
tile2.src='../images/test/tile2.png';
break;
case "tile3":
tile3.onload = function() {
context.drawImage(tile3, posX, posY, 64, 64);
tile3.src='../images/test/tile3.png';
break;
}
posX+=64;
}
posX=0;
posY+=64;
}
</script>
</body>
如您所见,我的3个开关选项现在都在等待图像加载之前加载它。
我在某个地方看到它可能与FOR循环有关,我必须使用一个IIFE,我在这里找到更多:What is the (function() { } )() construct in JavaScript?然而,我完全不熟悉这个术语/概念,我也不知道我是否在正确的轨道。
我也试图通过外部js加载它,然后在body标签中加载on =“drawTileMap()”,但是这会引发更加有趣的行为,因为它实际上似乎加载了随机磁贴而不是整个网格。
任何帮助非常感谢!
我建议不要沿着你在第二个代码块中尝试的路线走下去。保持资源加载例程和画布渲染功能分离(正如您在第一个代码示例中所尝试的那样)以便更好地进行维护。 JavaScript是一种基于异步事件的语言,使用它对您有利。
我已将您的代码分成两个函数。检查是否所有图像都已加载,并在这种情况下调用第二个函数(作为参数传递给它)。
当您感到舒适并理解我的示例如何工作时,您应该阅读JavaScript Promises(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise),因为它们是一种更通用,更好的方法来处理带回调的异步操作。
示例代码如下:
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
// 3X3 GRID
var mapArray = [
["tile1", "tile3", "tile1"],
["tile1", "tile1", "tile2"],
["tile3", "tile1", "tile2"]
];
var tile1 = new Image();
var tile2 = new Image();
var tile3 = new Image();
var nrOfImagesLoaded = 0;
// Using base64 datauri's, so the script doesn't depend on external resources
tile1.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAZElEQVR42u3QAQ0AAAjDMO5fNGCD0GUKmq7a/xYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgfgMNmH/BjHDEMQAAAABJRU5ErkJggg==';
tile2.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAY0lEQVR42u3QAQ0AAAjDMO5fNGCD0M1BU70/LgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMD9Bs3Jf8EvyPO9AAAAAElFTkSuQmCC';
tile3.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAYklEQVR42u3QAQ0AAAgDoL9/aM3hhAg0mcljFSBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAu5bjgl/wXGcqdoAAAAASUVORK5CYII=';
tile1.onload = function() {nrOfImagesLoaded++;}
tile2.onload = function() {nrOfImagesLoaded++;}
tile3.onload = function() {nrOfImagesLoaded++;}
// Function that takes another function as an argument and calls it when
// all 3 images have been loaded
function callWhenImagesLoaded(callback) {
// Call the function when all 3 tiles have been loaded
if(nrOfImagesLoaded == 3) {
callback();
// Otherwise poll again in 500 milliseconds to see if they are loaded
} else {
setTimeout(function() { callWhenImagesLoaded(callback) }, 500);
}
}
// Call this, when all images are loaded
function allImagesAreNowLoaded() {
var posX = 0;
var posY = 0;
for (var i = 0; i < mapArray.length; i++) {
for (var j = 0; j < mapArray[i].length; j++) {
switch (mapArray[i][j]) {
case "tile1":
context.drawImage(tile1, posX, posY, 64, 64);
break;
case "tile2":
context.drawImage(tile2, posX, posY, 64, 64);
break;
case "tile3":
context.drawImage(tile3, posX, posY, 64, 64);
break;
}
posX += 64;
}
posX = 0;
posY += 64;
}
}
// Tie it all togther - call allImagesAreNowLoaded when all 3 tiles have been loaded
callWhenImagesLoaded(allImagesAreNowLoaded);
<canvas id="canvas" width="200px" height="200px"></canvas>