HTML5在带有for循环的画布上绘制图片?

时间:2012-03-07 01:12:02

标签: javascript image html5 canvas draw

所以,我想用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>

3 个答案:

答案 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()

};
祝你好运!