javascript - HTML5 drawing pictures on a canvas with a for loop? - Stack Overflow

So, I want to create a minecraft website theme using HTML5.I am a bit shaky in HTML5Javascript(haven

So, I want to create a minecraft website theme using HTML5. I am a bit shaky in HTML5/Javascript(haven't used it in a while), and I need some help. I am trying to calculate a number of 16x16px tiles that can fit on the screen. Then, randomly "generate a map" for the background of the screen. Then, I use the same 2 for loops that generate the map to fill the screen with the tiles(which are assigned picture paths during the generation process). The problem is, the canvas is pletely white. Can anyone pick out the problem, and give me any tips if possible? Thanks in advance! Here is my HTML5 code:

<!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>

So, I want to create a minecraft website theme using HTML5. I am a bit shaky in HTML5/Javascript(haven't used it in a while), and I need some help. I am trying to calculate a number of 16x16px tiles that can fit on the screen. Then, randomly "generate a map" for the background of the screen. Then, I use the same 2 for loops that generate the map to fill the screen with the tiles(which are assigned picture paths during the generation process). The problem is, the canvas is pletely white. Can anyone pick out the problem, and give me any tips if possible? Thanks in advance! Here is my HTML5 code:

<!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>
Share Improve this question asked Mar 7, 2012 at 1:12 Flafla2Flafla2 5457 silver badges12 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 3

There is a lot going on here to explain. I tested the code below and got it to work, but I simply used one image over and over. Hopefully, this will work when merged with your code. Place the code, below, in place of your for loops (i.e., after var height and before function getImageNameFromRand).

First off, your code is defining all vars in the global namespace, so the img var is getting replaced each time through the original loop, along with its src and onload function ,etc. Furthermore, the x and y that increment the for loops get referenced through closure in the onload function, but because they are only incremented during the outside loop (not in the onload function) they are both set to their ending values during the onload call (the ending values when the original loop ran).

Also, try and put all your script into an anonymous function like (function () { YOUR CODE HERE } )(). This way you won't be adding to the global namespace with the local vars and the onload will have what it needs because of closure. I tested putting everything into the anonymous function and it worked for me.

Hopefully, I copied and pasted this all correctly. Please ment if it is off. Good Luck!!!

//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;
    }
}

When you do the following:

img.onload = function(){
    return function() {
        ctx.drawImage(img,x*16,y*16);
    };
};

You are attempting to create a closure over img so that inside of the onload handler it will refer to the image that you created in that iteration of the loop.

But you aren't quite doing that. Instead, the onload handler is just defining an anonymous function and then doing nothing.

img.onload = function(img){
    return function() {
        ctx.drawImage(img,x*16,y*16);
    };
}(img);

If you change it so that you are immediately calling the anonymous function and passing in img, then you will close over img (from the for loop context) and it will do what you want.

If the outer anonymous function isn't immediately called, then it will bee the onload handler for the image. And nothing will happen. Leading to a blank canvas.

The problem is that in your for loop, you are drawing the image over and over on top of each other. If you break out of the forloops entirely after the first run(x=0, y=0), you will see a single tile of your random image on position 0,0. When it goes through the entire double for loop, your last image is drawn on the bottom corner of the canvas, which creates the 'blank white canvas' you are seeing. You need to have it draw a 'pre filled' canvas of random tiles. This also means that your for loops need to be inside the onload() function because your background only gets drawn once, not hundreds/thousands of times.

Look for html5 canvas patterns/tiles then work from there.

also, your onload function doesn't need the inside function, you could have it as something like this:

img.onload = function(){

    // - nested for loops
    //   -> generate a tile pattern to fit the entire canvas

    // - ctx.drawImage()

};

Good luck!

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744193387a4562539.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信