简体   繁体   English

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

[英]HTML5 drawing pictures on a canvas with a for loop?

So, I want to create a minecraft website theme using HTML5. 所以,我想用HTML5创建一个Minecraft网站主题。 I am a bit shaky in HTML5/Javascript(haven't used it in a while), and I need some help. 我在HTML5 / Javascript中有点摇摇欲坠(暂时没用过它),我需要一些帮助。 I am trying to calculate a number of 16x16px tiles that can fit on the screen. 我正在尝试计算一些可以放在屏幕上的16x16px瓷砖。 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). 然后,我使用相同的2 for循环生成地图,用填充图块填充屏幕(在生成过程中分配图片路径)。 The problem is, the canvas is completely white. 问题是,画布完全是白色的。 Can anyone pick out the problem, and give me any tips if possible? 任何人都可以选择问题,并在可能的情况下给我任何提示吗? Thanks in advance! 提前致谢! Here is my HTML5 code: 这是我的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>

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 (ie, after var height and before function getImageNameFromRand). 将代码放在下面,代替for循环(即在var高度之后和函数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. 首先,您的代码定义了全局命名空间中的所有变量,因此每次通过原始循环时都会替换img var,以及它的src和onload函数等。 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). 此外,增加for循环的x和y在onload函数中通过闭包引用,但由于它们仅在外部循环(而不是onload函数)中递增,因此它们在onload调用期间都被设置为它们的结束值(原始循环运行时的结束值)。

Also, try and put all your script into an anonymous function like (function () { YOUR CODE HERE } )(). 另外,尝试将所有脚本放入匿名函数中,如(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. 这样您就不会使用本地变量添加到全局命名空间,并且onload将因为闭包而具有所需的内容。 I tested putting everything into the anonymous function and it worked for me. 我测试了将所有内容放入匿名函数中,它对我有用。

Hopefully, I copied and pasted this all correctly. 希望我能正确地复制和粘贴这一切。 Please comment 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. 您正在尝试在img上创建一个闭包,以便在onload处理程序内部引用您在循环迭代中创建的图像。

But you aren't quite doing that. 但你并没有这么做。 Instead, the onload handler is just defining an anonymous function and then doing nothing. 相反, onload处理程序只是定义一个匿名函数,然后什么都不做。

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. 如果您更改它以便立即调用匿名函数并传入img ,那么您将关闭img (来自for循环上下文)并且它将执行您想要的操作。

If the outer anonymous function isn't immediately called, then it will become the onload handler for the image. 如果没有立即调用外部匿名函数,那么它将成为图像的onload处理程序。 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. 如果在第一次运行后完全脱离forloops(x = 0,y = 0),您将在位置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. 当它遍历整个double for循环时,最后一个图像将绘制在画布的底角,这将创建您正在看到的“空白白色画布”。 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. 这也意味着你的for循环需要在onload()函数中,因为你的背景只被绘制一次,而不是几百次/几千次。

Look for html5 canvas patterns/tiles then work from there. 寻找html5画布图案/瓷砖然后从那里工作。

also, your onload function doesn't need the inside function, you could have it as something like this: 另外,你的onload函数不需要inside函数,你可以像这样:

img.onload = function(){

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

    // - ctx.drawImage()

};

Good luck! 祝好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM