【问题标题】:Images from previous functions are not drawn in the background (Canvas)来自先前函数的图像不在背景中绘制(画布)
【发布时间】:2012-09-27 07:33:48
【问题描述】:

我的问题是关于在 HTML Canvas 中使用函数进行绘图的。 我尝试用 Canvas 绘制“交易卡”来创建游戏。 所以我决定编写一个函数来获取所有必要的信息来绘制不同的卡片。 对于一张卡 - 没问题。但是,如果我尝试在第一张卡片上再画一张卡片,则可以通过第二张卡片看到第一张卡片的图像。

这里是源代码:

function RoundRect(x,y,scale,lvl,mage,headline,text,HP,MP,AtckP,DefP,MDefP){
            //Kartenumriss zeichnen
            context.strokeStyle="rgb(0,0,0)";
            context.fillStyle="rgb(180,180,180)";
            context.lineWidth=2*scale;
            context.beginPath();
            context.moveTo(x+10*scale,y+0*scale);
            context.lineTo(x+90*scale,y+0*scale);
            context.arcTo(x+100*scale,y+0*scale,x+100*scale,y+10*scale,10*scale);
            context.lineTo(x+100*scale,y+110*scale);
            context.arcTo(x+100*scale,y+120*scale,x+90*scale,y+120*scale,10*scale);
            context.lineTo(x+10*scale,y+120*scale);
            context.arcTo(x+0*scale,y+120*scale,x+0*scale,y+110*scale,10*scale);
            context.lineTo(x+0*scale,y+10*scale);
            context.arcTo(x+0*scale,y+0*scale,x+10*scale,y+0*scale,10*scale);
            context.fill();
            context.stroke();
            //innerer Kartenumriss zeichnen
            context.strokeStyle="rgb(0,0,0)";
            context.lineWidth=2*scale;
            context.beginPath();
            context.moveTo(x+20*scale,y+10*scale)
            context.lineTo(x+80*scale,y+10*scale);
            context.arcTo(x+80*scale,y+20*scale,x+90*scale,y+20*scale,10*scale);
            context.lineTo(x+90*scale,y+100*scale);
            context.arcTo(x+80*scale,y+100*scale,x+80*scale,y+110*scale,10*scale);
            context.lineTo(x+20*scale,y+110*scale);
            context.arcTo(x+20*scale,y+100*scale,x+10*scale,y+100*scale,10*scale);
            context.lineTo(x+10*scale,y+20*scale);
            context.arcTo(x+20*scale,y+20*scale,x+20*scale,y+10*scale,10*scale);
            context.lineCap="square";
            context.stroke();
            //Textfeld zeichnen
            context.strokeStyle="rgb(0,0,0)";
            context.fillStyle="rgb(0,0,0)";
            context.lineWidth=2*scale;
            context.beginPath();
            context.moveTo(x+90*scale,y+65*scale);
            context.lineTo(x+90*scale,y+100*scale);
            context.arcTo(x+80*scale,y+100*scale,x+80*scale,y+110*scale,10*scale);
            context.lineTo(x+20*scale,y+110*scale);
            context.arcTo(x+20*scale,y+100*scale,x+10*scale,y+100*scale,10*scale);
            context.lineTo(x+10*scale,y+65*scale);
            context.arcTo(x+20*scale,y+65*scale,x+20*scale,y+75*scale,10*scale);
            context.lineTo(x+80*scale,y+75*scale)
            context.arcTo(x+80*scale,y+65*scale,x+90*scale,y+65*scale,10*scale)
            context.lineCap="square";
            context.fill();
            context.stroke();
            //lvl zeichnen
            shift=0;
            for(var greystar=0;greystar<=4; greystar++){
                context.strokeStyle="rgb(100,100,100)";
                context.fillStyle="rgb(100,100,100)";
                context.beginPath();
                context.moveTo(shift+x+23.33*scale,y+112*scale);
                context.lineTo(shift+x+25.33*scale,y+118.66*scale);
                context.lineTo(shift+x+20*scale,y+114.53*scale);
                context.lineTo(shift+x+26.66*scale,y+114.53*scale);
                context.lineTo(shift+x+21.26*scale,y+118.66*scale);
                context.lineTo(shift+x+23.33*scale,y+112*scale);
                context.fill();
                shift+=13.5*scale;
            }
            shift=0;
            while(lvl>0){
                context.strokeStyle="yellow";
                context.fillStyle="yellow";
                context.beginPath();
                context.moveTo(shift+x+23.33*scale,y+112*scale);
                context.lineTo(shift+x+25.33*scale,y+118.66*scale);
                context.lineTo(shift+x+20*scale,y+114.53*scale);
                context.lineTo(shift+x+26.66*scale,y+114.53*scale);
                context.lineTo(shift+x+21.26*scale,y+118.66*scale);
                context.lineTo(shift+x+23.33*scale,y+112*scale);
                context.fill();
                shift+=13.5*scale;
                lvl--;
            }
            //Bild einbinden
            var chucknorris = new Image();
            chucknorris.onload = function() {
                context.drawImage(chucknorris,x+18*scale,y+18*scale,64*scale,49*scale);
            };
            chucknorris.src="pics/chucknorris.png";
            //Symbole einbinden
            //life
            var life = new Image();
            life.onload = function() {
                context.drawImage(life,x+87*scale,y+11*scale,7*scale,7*scale);
            };
            life.src="pics/heart_small.png";
            //magic
            var magic = new Image();
            magic.onload = function() {
                context.drawImage(magic,x+6*scale,y+11*scale,7*scale,7*scale);
            };
            magic.src="pics/magic_small.png";
            if(mage==true){
                //wand
                var wand = new Image();
                wand.onload = function() {
                    context.drawImage(wand,x+6*scale,y+102*scale,7*scale,7*scale);
                };
                wand.src="pics/wand_small.png";
            }
            else{
                //sword
                var sword = new Image();
                sword.onload = function() {
                    context.drawImage(sword,x+6*scale,y+102*scale,7*scale,7*scale);
                };
                sword.src="pics/sword_crossed_small.png";
            }
            //shield
            var shield = new Image();
            shield.onload = function() {
                context.drawImage(shield,x+85*scale,y+102*scale,7*scale,7*scale);
            };
            shield.src="pics/shield_small.png";
            //magic_shield
            var magic_shield = new Image();
            magic_shield.onload = function() {
                context.drawImage(magic_shield,x+91*scale,y+102*scale,7*scale,7*scale);
            };
            magic_shield.src="pics/magic_shield_small.png";
            //Text einfügen
            context.font = 'bold '+4*scale+'px Calibri';
            context.fillStyle = 'rgb(255,255,255)';
            context.fillText(headline,x+20*scale, y+80*scale);
            context.font = 'normal '+3*scale+'px Calibri';
            context.fillStyle = 'rgb(255,255,255)';
            wrapText(context, text, x+20*scale, y+85*scale, maxWidth, lineHeight, scale);
            //HP anzeigen
            context.font = 'bold 20pt Calibri';
            context.fillStyle = 'rgb(255,0,0)';
            var textmetric = context.measureText(HP);
            var textwidth = textmetric.width/2;
            context.fillText(HP,x-textwidth+90.25*scale, y+10*scale);
            //MP anzeigen
            context.fillStyle = 'rgb(0,0,255)';
            textmetric = context.measureText(MP);
            textwidth = textmetric.width/2;
            context.fillText(MP,x-textwidth+9.5*scale, y+10*scale);
            //AtckP anzeigen
            context.fillStyle = 'rgb(0,0,0)';
            textmetric = context.measureText(AtckP);
            textwidth = textmetric.width/2;
            context.fillText(AtckP,x-textwidth+9.5*scale, y+115*scale);
            //DefP und MDefP anzeigen
            context.fillStyle = 'rgb(0,0,0)';
            var DefAll = DefP+'/'+MDefP;
            textmetric = context.measureText(DefAll);
            textwidth = textmetric.width;
            context.fillText(DefAll,x-textwidth+98*scale, y+115*scale);
        };

我认为重要的部分在“//Bild einbinden”和“//Text einfügen”之间,但我不确定。

该函数稍后在测试代码中使用如下:

RoundRect(0,0,4,5,false,'Chuck Norris','Wenn Chuck Norris spricht, hört Gott zu!!! Chuck Norris` Tränen können Krebs heilen. Nur schade dass er niemals weint!!! Chuck Norris geht manchmal Blut spenden. Nur nie sein eigenes. Und wenn doch, dann mit ner Knarre und nem Eimer!!!','100','0','120','20','60');
RoundRect(100,120,4,2,false,'Chuck Norris Vers 0.3','Wenn Chuck Norris spricht, hört Gott zu!!! Chuck Norris` Tränen können Krebs heilen. Nur schade dass er niemals weint!!! Chuck Norris geht manchmal Blut spenden. Nur nie sein eigenes. Und wenn doch, dann mit ner Knarre und nem Eimer!!!','50','100','60','10','30');

结果如下:

Result

我希望有人可以帮助我。提前谢谢你(

编辑: 我想出了问题的一部分,但我仍然需要一个解决方案: 我试图在代码中设置一些“alert();”。结果很有趣:首先,第一张牌的背景被绘制出来。然后是第二张卡片的背景。之后,第一张牌的图像被抽出,然后是第二张牌的其他图像。因此,在绘制其他所有内容之后绘制的图像。 所以问题是如何告诉 Canvas 立即绘制图像,或者至少在函数内绘制。

【问题讨论】:

    标签: image html canvas


    【解决方案1】:

    你会在所有事情之后绘制图像,因为它们是在 Image.onLoad() 的回调中绘制的。

    这意味着该函数将首先渲染第一张卡片的背景,为您的 Image.onLoad 事件注册一个侦听器,然后返回,以便您可以进行第二次调用,它将渲染背景,并注册另一个侦听器对于新的 Image.onLoad 事件。然后在加载第一个图像时触发第一个侦听器,因此它会绘制图片,最后会触发第二个侦听器。因此你的结果。

    至于解决此问题的方法,您可以在绘制任何卡片之前加载图像,然后直接在函数中绘制它,避免等待加载,或者您必须使您的设计异步证明。您可以在此处获取有关异步编程的信息:http://www.html5rocks.com/en/tutorials/async/deferred/?redirect_from_locale=why

    编辑:第二个解决方案可以帮助第一个解决方案(对应于 enzhflep 的答案)。文章推荐使用jquery来处理加载多张图片等异步事件。但是如果你不需要jQuery,你也可以编写一个小的javascript对象,它可以注册要加载的图像,并在所有图像加载时触发一个监听器。 This ressource 似乎提供了那个特定的对象。

    【讨论】:

    • 也谢谢你。无论如何,我都会阅读这篇文章。但我想先测试一下 enhzflep 的解决方案。^^
    【解决方案2】:

    不是问题。你的英语很好。 (你提到的翻译有点奇怪'提前谢谢你)

    正如您似乎开始发现的那样,问题是由于加载图像所花费的时间..

    每次抽卡时,都会加载其中的每张图片。一旦加载了每个图像,它的 onload 处理程序就会触发并将其绘制到画布上。现在,问题在于,有时当您绘制第二张卡片时,第一张卡片中的图像仍在加载。这意味着第二张卡片的部分内容在卡片 1 的图像加载之前已被绘制。当它们最终加载时,它们被绘制在 card2 的顶部。

    您可以通过在页面的 init 函数中加载图像来解决此问题。

    这是我使用的解决方案:

    var canvas, context;
    
    var chucknorris = new Image();
    var life = new Image();
    var magic = new Image();
    var wand = new Image();
    var sword = new Image();
    var shield = new Image();
    var magic_shield = new Image();
    
    function myInit()
    {
        chucknorris.src="img/girl.png"; //"pics/chucknorris.png";
        life.src="img/heartSmall.jpg"; //"pics/heart_small.png";
        magic.src="img/magicSmall.jpg"; //"pics/magic_small.png";
        wand.src="img/magicSmall.jpg"; //"pics/wand_small.png";
        sword.src="img/magicSmall.jpg"; //"pics/sword_crossed_small.png";
        shield.src="img/close.png"; //pics/shield_small.png";
        magic_shield.src="img/magicSmall.jpg"; //"pics/magic_shield_small.png";
    
        canvas = document.createElement('canvas');
        canvas.setAttribute('width', '400');
        canvas.setAttribute('height', '800');
        context = canvas.getContext('2d');
        document.body.appendChild(canvas);
    
        RoundRect(0,0,2,5,false,'Chuck Norris','Wenn Chuck Norris spricht, hört Gott zu!!! Chuck Norris` Tränen können Krebs heilen. Nur schade dass er niemals weint!!! Chuck Norris geht manchmal Blut spenden. Nur nie sein eigenes. Und wenn doch, dann mit ner Knarre und nem Eimer!!!','100','0','120','20','60');
    
        RoundRect(128,0,2,5,false,'Pussy Galore','She loves Austin Powers','100','0','120','20','60');
    }
    
    
    
    function RoundRect(x,y,scale,lvl,mage,headline,text,HP,MP,AtckP,DefP,MDefP)
    {
        var mImages
    
        //Kartenumriss zeichnen
        context.globalCompositeOperation = "src-over";
    
        context.strokeStyle="rgb(0,0,0)";
        context.fillStyle="rgb(180,180,180)";
        context.lineWidth=2*scale;
        context.beginPath();
        context.moveTo(x+10*scale,y+0*scale);
        context.lineTo(x+90*scale,y+0*scale);
        context.arcTo(x+100*scale,y+0*scale,x+100*scale,y+10*scale,10*scale);
        context.lineTo(x+100*scale,y+110*scale);
        context.arcTo(x+100*scale,y+120*scale,x+90*scale,y+120*scale,10*scale);
        context.lineTo(x+10*scale,y+120*scale);
        context.arcTo(x+0*scale,y+120*scale,x+0*scale,y+110*scale,10*scale);
        context.lineTo(x+0*scale,y+10*scale);
        context.arcTo(x+0*scale,y+0*scale,x+10*scale,y+0*scale,10*scale);
        context.fill();
        context.stroke();
        //innerer Kartenumriss zeichnen
        context.strokeStyle="rgb(0,0,0)";
        context.lineWidth=2*scale;
        context.beginPath();
        context.moveTo(x+20*scale,y+10*scale)
        context.lineTo(x+80*scale,y+10*scale);
        context.arcTo(x+80*scale,y+20*scale,x+90*scale,y+20*scale,10*scale);
        context.lineTo(x+90*scale,y+100*scale);
        context.arcTo(x+80*scale,y+100*scale,x+80*scale,y+110*scale,10*scale);
        context.lineTo(x+20*scale,y+110*scale);
        context.arcTo(x+20*scale,y+100*scale,x+10*scale,y+100*scale,10*scale);
        context.lineTo(x+10*scale,y+20*scale);
        context.arcTo(x+20*scale,y+20*scale,x+20*scale,y+10*scale,10*scale);
        context.lineCap="square";
        context.stroke();
        //Textfeld zeichnen
        context.strokeStyle="rgb(0,0,0)";
        context.fillStyle="rgb(0,0,0)";
        context.lineWidth=2*scale;
        context.beginPath();
        context.moveTo(x+90*scale,y+65*scale);
        context.lineTo(x+90*scale,y+100*scale);
        context.arcTo(x+80*scale,y+100*scale,x+80*scale,y+110*scale,10*scale);
        context.lineTo(x+20*scale,y+110*scale);
        context.arcTo(x+20*scale,y+100*scale,x+10*scale,y+100*scale,10*scale);
        context.lineTo(x+10*scale,y+65*scale);
        context.arcTo(x+20*scale,y+65*scale,x+20*scale,y+75*scale,10*scale);
        context.lineTo(x+80*scale,y+75*scale)
        context.arcTo(x+80*scale,y+65*scale,x+90*scale,y+65*scale,10*scale)
        context.lineCap="square";
        context.fill();
        context.stroke();
        //lvl zeichnen
        shift=0;
        for(var greystar=0;greystar<=4; greystar++)
        {
            context.strokeStyle="rgb(100,100,100)";
            context.fillStyle="rgb(100,100,100)";
            context.beginPath();
            context.moveTo(shift+x+23.33*scale,y+112*scale);
            context.lineTo(shift+x+25.33*scale,y+118.66*scale);
            context.lineTo(shift+x+20*scale,y+114.53*scale);
            context.lineTo(shift+x+26.66*scale,y+114.53*scale);
            context.lineTo(shift+x+21.26*scale,y+118.66*scale);
            context.lineTo(shift+x+23.33*scale,y+112*scale);
            context.fill();
            shift+=13.5*scale;
        }
        shift=0;
        while(lvl>0)
        {
            context.strokeStyle="yellow";
            context.fillStyle="yellow";
            context.beginPath();
            context.moveTo(shift+x+23.33*scale,y+112*scale);
            context.lineTo(shift+x+25.33*scale,y+118.66*scale);
            context.lineTo(shift+x+20*scale,y+114.53*scale);
            context.lineTo(shift+x+26.66*scale,y+114.53*scale);
            context.lineTo(shift+x+21.26*scale,y+118.66*scale);
            context.lineTo(shift+x+23.33*scale,y+112*scale);
            context.fill();
            shift+=13.5*scale;
            lvl--;
        }
        //Bild einbinden
        context.drawImage(chucknorris,x+18*scale,y+18*scale,64*scale,49*scale);
    
        //Symbole einbinden
        //life
        context.drawImage(life,x+87*scale,y+11*scale,7*scale,7*scale);
    
        //magic
            context.drawImage(magic,x+6*scale,y+11*scale,7*scale,7*scale);
        if(mage==true)
        {
            context.drawImage(wand,x+6*scale,y+102*scale,7*scale,7*scale);
        }
        else{
                context.drawImage(sword,x+6*scale,y+102*scale,7*scale,7*scale);
        }
        //shield
            context.drawImage(shield,x+85*scale,y+102*scale,7*scale,7*scale);
    
            //magic_shield
    //  magic_shield.onload = function() {
            context.drawImage(magic_shield,x+91*scale,y+102*scale,7*scale,7*scale);
    //  };
    
        //Text einfügen
        context.font = 'bold '+4*scale+'px Calibri';
        context.fillStyle = 'rgb(255,255,255)';
        context.fillText(headline,x+20*scale, y+80*scale);
        context.font = 'normal '+3*scale+'px Calibri';
        context.fillStyle = 'rgb(255,255,255)';
        wrapText(context, text, x+20*scale, y+85*scale, maxWidth, lineHeight, scale);
        //HP anzeigen
        context.font = 'bold 20pt Calibri';
        context.fillStyle = 'rgb(255,0,0)';
        var textmetric = context.measureText(HP);
        var textwidth = textmetric.width/2;
        context.fillText(HP,x-textwidth+90.25*scale, y+10*scale);
        //MP anzeigen
        context.fillStyle = 'rgb(0,0,255)';
        textmetric = context.measureText(MP);
        textwidth = textmetric.width/2;
        context.fillText(MP,x-textwidth+9.5*scale, y+10*scale);
        //AtckP anzeigen
        context.fillStyle = 'rgb(0,0,0)';
        textmetric = context.measureText(AtckP);
        textwidth = textmetric.width/2;
        context.fillText(AtckP,x-textwidth+9.5*scale, y+115*scale);
        //DefP und MDefP anzeigen
        context.fillStyle = 'rgb(0,0,0)';
        var DefAll = DefP+'/'+MDefP;
        textmetric = context.measureText(DefAll);
        textwidth = textmetric.width;
        context.fillText(DefAll,x-textwidth+98*scale, y+115*scale);
    };
    

    【讨论】:

    • 如果您的连接速度足够快,可以在需要绘制图像之前加载图像,那应该可以工作。也许您应该在调用 RoundRect 之前检查所有图像是否已加载。
    • 谢谢。我会试试这个,稍后再发布结果。 @TonioElGringo:你会如何检查这个?
    • @TonioElGringo - 这是一个很好的观点。感谢您提供我忽略的清晰度!从本地主机加载资源总是比通过电线或空气更快:)
    • @Sandro 我用一个链接编辑了我的答案,该链接指向一篇关于如何加载多个图像,并在加载所有图像时调用一个函数的文章。
    • 再次感谢。应该管用。至少我希望如此。我稍后会发布结果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-20
    • 1970-01-01
    • 2019-04-16
    • 2016-08-05
    • 1970-01-01
    相关资源
    最近更新 更多