所以,我想用HTML5创建一个Minecraft网站主题。我在HTML5 / Javascript中有点摇摇欲坠(暂时没用过它),我需要一些帮助。我正在尝试计算一些可以放在屏幕上的16x16px瓷砖。然后,随机“生成地图”作为屏幕背景。然后,我使用相同的2 for循环生成地图,用填充图块填充屏幕(在生成过程中分配图片路径)。问题是,画布完全是白色的。任何人都可以选择问题,并在可能的情况下给我任何提示吗?提前致谢!这是我的HTML5代码:
<!DOCTYPE html>
<html>
<head>
<title>Minecraft Background Check</title>
</head>
<body>
<canvas id="bg" style="position:fixed; top:0; left:0; border:1px solid #c3c3c3; width: 100%; height: 100%;"></canvas>
<script type="text/javascript">
"use strict";
var c = document.getElementById("bg");
var ctx = c.getContext("2d");
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
var width = Math.ceil(window.innerWidth / 16);
var height = Math.ceil(window.innerHeight / 16);
for (var x=0;x<width;x++)
{
for(var y=0;y<height;y++)
{
var rand = Math.floor(Math.random()*11);
var texLoc = getImageNameFromRand(rand,y,height);
var img=new Image();
img.onload = function(){
return function() {
ctx.drawImage(img,x*16,y*16);
};
};
img.src=texLoc;
}
}
function getImageNameFromRand(rand,yVal,maxY)
{
var dirt = 'dirt.png';
var stone = 'stone.png';
var cobble = 'cobble.png';
var mosscobble = 'mosscobble.png';
var bedrock = 'bedrock.png';
if(yVal===0)
{
return dirt;
} else if(yVal<3)
{
if(rand < 7) {
return dirt; }
else {
return stone; }
} else if(yVal<5)
{
if(rand < 4) {
return dirt; }
else {
return stone; }
} else if(yVal<maxY-2)
{
if(rand === 0) {
return dirt; }
else if(rand < 4) {
return cobble; }
else if(rand < 5) {
return mosscobble; }
else {
return stone; }
} else if(yVal<maxY-1)
{
if(rand < 4) {
return bedrock; }
else {
return stone; }
} else if(yVal<maxY)
{
if(rand < 7) {
return bedrock; }
else {
return stone; }
} else {
return bedrock; }
return bedrock;
}
</script>
</body>
</html>
答案 0 :(得分:3)
这里有很多解释。我测试了下面的代码,并让它工作,但我只是一遍又一遍地使用一个图像。希望这可以在与您的代码合并时使用。将下面的代码放在for循环的位置(即var高度之后和函数getImageNameFromRand之前)。
首先,您的代码定义了全局命名空间中的所有变量,因此每次通过原始循环时都会替换img var,以及它的src和onload函数等。此外,增加for循环的x和y在onload函数中通过闭包引用,但由于它们仅在外部循环(而不是onload函数)中递增,因此它们在onload调用期间都被设置为它们的结束值(原始循环运行时的结束值。)
另外,尝试将所有脚本放入匿名函数中,如(function(){YOUR CODE HERE})()。这样您就不会使用本地变量添加到全局命名空间,并且onload将因为闭包而具有所需的内容。我测试了将所有内容放入匿名函数中,它对我有用。
希望我能正确地复制和粘贴这一切。请评论是否关闭。祝你好运!!!
//Copy this code in place of your original "for" loop:
var imgs = [];
var imgIndex = 0;
for (var x = 0; x < width; x++){
for(var y = 0; y < height; y++){
var rand = Math.floor(Math.random() * 11);
var texLoc = getImageNameFromRand(rand, y, height);
imgs[imgIndex] = new Image();
imgs[imgIndex].onload = (function () {
var thisX = x * 16;
var thisY = y * 16;
return function () {
ctx.drawImage(this, thisX, thisY);
};
}());
imgs[imgIndex].src = texLoc;
imgIndex += 1;
}
}
答案 1 :(得分:1)
执行以下操作时:
img.onload = function(){
return function() {
ctx.drawImage(img,x*16,y*16);
};
};
您正在尝试在img
上创建一个闭包,以便在onload
处理程序内部引用您在该循环迭代中创建的图像。
但你并没有这么做。相反,onload
处理程序只是定义一个匿名函数,然后什么都不做。
img.onload = function(img){
return function() {
ctx.drawImage(img,x*16,y*16);
};
}(img);
如果您更改它以便立即调用匿名函数并传入img
,那么您将关闭img
(来自for
循环上下文)并且它将执行你想要什么。
如果没有立即调用外部匿名函数,那么它将成为图像的onload处理程序。什么都不会发生。通向空白画布。
答案 2 :(得分:0)
问题在于,在你的for循环中,你正在一个又一个地在顶部上绘制图像。如果在第一次运行后完全脱离forloops(x = 0,y = 0),您将在位置0,0上看到随机图像的单个图块。当它遍历整个double for循环时,最后一个图像将绘制在画布的底角,这将创建您正在看到的“空白白色画布”。你需要让它绘制一个随机瓷砖的“预填充”画布。这也意味着你的for循环需要在onload()函数中,因为你的背景只被绘制一次,而不是数百次/数千次。
查找html5画布图案/图块然后从那里开始工作。
另外,你的onload函数不需要内部函数,你可以像这样:
img.onload = function(){
// - nested for loops
// -> generate a tile pattern to fit the entire canvas
// - ctx.drawImage()
};
祝你好运!