【问题标题】:HTML5 Canvas set z-indexHTML5 Canvas 设置 z-index
【发布时间】:2012-02-28 06:16:54
【问题描述】:

是否可以在 HTML5 画布中设置绘制对象的 z-index?

我正在尝试获取它,以便一个对象可以在“玩家”之前,而另一个对象可以在“玩家”之后

【问题讨论】:

标签: javascript html


【解决方案1】:

抱歉,不,canvas 元素将有它的 z-index 并且在其上绘制的任何内容都将在该层上。

如果您指的是画布上的不同事物,那么是的,任何被绘制的东西都会被绘制在之前的任何东西之上。

【讨论】:

    【解决方案2】:

    只需先画它后面的东西,然后是东西,然后是其他对象。

    要进行命中测试,您可能需要在显示列表上向后迭代,测试每个对象。如果您非常了解对象边界,这将起作用。

    或者您可能想尝试一些标准的图形技巧,例如将相同的对象绘制到另一个内存画布上,并为每个绘制的对象使用独特的颜色:要进行测试,只需检查内存画布上的像素颜色。整洁;-)

    【讨论】:

      【解决方案3】:

      我发现一个对我有用的解决方案(并且摆脱了闪烁,欢呼!)是使用两个画布。 (或更多)

      我假设您正在制作某种游戏(因为您提到了玩家)并以此为例。

      您可以从 windows 的工作方式中获取一个页面,然后将一个画布作为背景,然后在其上放置另一个画布作为您的播放器画布。您可以将播放器画布标记为“脏”或在更改时更改,并且仅在需要时重绘更改的图层。这意味着您仅在玩家移动或采取行动时更新第二个画布。

      这个方法可以走得更远,你可以为 HUD 添加第三个画布,上面有游戏统计数据,只有当玩家的统计数据改变时才会改变。

      html 可能看起来像这样:

      <canvas id="background-canvas" height="500" width="1000" style="border:1px solid #000000;"></canvas>
      <canvas id="player-canvas" height="500" width="1000" style="border:1px solid #000000;"></canvas>
      <canvas id="hud-canvas" height="500" width="1000" style="border:1px solid #000000;"></canvas>
      

      【讨论】:

        【解决方案4】:

        是的..有点是的。您可以使用globalCompositeOperation“绘制”现有像素。

        ctx.globalCompositeOperation='destination-over';
        

        这是一个例子和一个演示:

        var canvas=document.getElementById("canvas");
        var ctx=canvas.getContext("2d");
        
        var cx=100;
        
        drawCircle()
        cx+=20;
        
        ctx.globalCompositeOperation='destination-over';
        
        $("#test").click(function(){
          drawCircle();
          cx+=20;
        });
        
        function drawCircle(){
          ctx.beginPath();
          ctx.arc(cx,150,20,0,Math.PI*2);
          ctx.closePath();
          ctx.fillStyle=randomColor();
          ctx.fill();
        }
        
        function randomColor(){ 
          return('#'+Math.floor(Math.random()*16777215).toString(16));
        }
        body{ background-color: ivory; }
        canvas{border:1px solid red;}
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
        <button id="test">Draw new circle behind.</button><br>
        <canvas id="canvas" width=300 height=300></canvas>

        【讨论】:

        • 你为什么说“有点”?对我来说,这似乎是这里唯一真正的解决方案。
        • 我说“有点”是因为合成不如重构图纸以首先显示正确的 z 分层那样灵活。合成只涉及 2 个“层”。一层是画布上的现有像素,第二层是新绘制的像素。重构以绘制适当分层的图形会产生所需的层数。
        • stackoverflow 很棒!
        • 喜欢使用toString(16) - 你教会了我一个新技巧:)
        • @conor909 它将数字转换为十六进制格式,然后返回为字符串,因此基本上它允许您轻松地将数字 rgb 值转换为其十六进制字符串等价物。尝试在控制台中运行上面显示的 randomColor() 函数以查看它的实际效果
        【解决方案5】:

        或者您可以简单地使用包含要绘制的对象的数组,然后使用每个子对象的zIndex 属性对该数组进行排序。然后你 jist 迭代那个数组并绘制。

        var canvas = document.querySelector('#game-canvas');
        var ctx = canvas.getContext('2d');
        
        // Define our shape "class".
        var Shape = function (x, y, z, width, height) {
          this.x = x;
          this.y = y;
          this.zIndex = z;
          this.width = width;
          this.height = height;
        };
        // Define the shape draw function.
        Shape.prototype.draw = function () {
          ctx.fillStyle = 'lime';
          ctx.fillRect(this.x, this.y, this.width, this.height);
        };
        
        // let's store the objects to be drawn.
        var objects = [
          new Shape(10, 10, 0, 30, 30), // should be drawn first.
          new Shape(50, 10, 2, 30, 30), // should be drawn third.
          new Shape(90, 10, 1, 30, 30)  // should be drawn second.
        ];
        
        // For performance reasons, we will first map to a temp array, sort and map the temp array to the objects array.
        var map = objects.map(function (el, index) {
          return { index : index, value : el.zIndex };
        });
        
        // Now we need to sort the array by z index.
        map.sort(function (a, b) {
          return a.value - b.value;
        });
        
        // We finaly rebuilt our sorted objects array.
        var objectsSorted = map.map(function (el) {
          return objects[el.index];
        });
        
        // Now that objects are sorted, we can iterate to draw them.
        for (var i = 0; i < objectsSorted.length; i++) {
          objectsSorted[i].draw();
        }
        
        // Enjoy !
        

        请注意,我没有测试该代码并将其写在我的手机上,因此可能会有拼写错误,但我希望这应该可以理解其中的原理。

        【讨论】:

        • 我认为map.sort(function (a, b) { return a - b; }); 应该是map.sort(function (a, b) { return a.value - b.value; });,我认为你不能只减去两个对象。
        猜你喜欢
        • 2012-12-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-27
        • 1970-01-01
        • 2021-01-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多