繁体   English   中英

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

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

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

这里有很多解释。 我测试了下面的代码,并让它工作,但我只是一遍又一遍地使用一个图像。 希望这可以在与您的代码合并时使用。 将代码放在下面,代替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;
    }
}

执行以下操作时:

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处理程序。 什么都不会发生。 通向空白画布。

问题是,在你的循环,你一遍又一遍地绘制的图像, 彼此的顶部 如果在第一次运行后完全脱离forloops(x = 0,y = 0),您将在位置0,0上看到随机图像的单个图块。 当它遍历整个double for循环时,最后一个图像将绘制在画布的底角,这将创建您正在看到的“空白白色画布”。 你需要让它绘制一个随机瓷砖的“预填充”画布。 这也意味着你的for循环需要在onload()函数中,因为你的背景只被绘制一次,而不是几百次/几千次。

寻找html5画布图案/瓷砖然后从那里工作。

另外,你的onload函数不需要inside函数,你可以像这样:

img.onload = function(){

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

    // - ctx.drawImage()

};

祝好运!

暂无
暂无

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

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