画布:动画一个简单的星场

时间:2013-06-18 14:10:49

标签: javascript html5 performance animation canvas

我对Canvas比较陌生。找到我的脚我正在创建一个简单的街机游戏。

我的问题是关于CPU性能/效率。

我在黑色背景上创建了100个随机定位的白点作为星星。在每个requestAnimationFrame上,星星向左移动一个像素,当它们到达最左侧时,该列像素位于屏幕的最右侧。

使用requestAnimationFrame我正在调用以下函数:

bgAnimateId = requestAnimationFrame( scrollBg );

function scrollBg() {
    var imgData = ctx.getImageData( 0, 0, 1, canvas.height );
    var areaToMoveLeft = ctx.getImageData( 1, 0, canvas.width-1, canvas.height );
    ctx.putImageData( areaToMoveLeft, 0, 0 );
    ctx.putImageData( imgData, canvas.width-1, 0 );
    bgAnimateId = requestAnimationFrame( scrollBg );
}

我担心的是 - 创建100个小画布元素(或100个div)并为其制作动画会更好吗,或者更好地利用我上面使用过的像素方法。

非常感谢你提前给予的帮助/指导: - )

1 个答案:

答案 0 :(得分:5)

事实证明,context.getImageDatacontext.putImageData执行起来非常昂贵并且有100幅画布太多。

所以这是制定有效淘选星空的计划:

使用context.drawImage非常有效,而且执行起来不是很昂贵。

以下是如何在画布上绘制随机星空,然后将该画布保存为图像:

// draw a random starfield on the canvas
bkCtx.beginPath();
bkCtx.fillStyle="darkblue";
bkCtx.rect(0,0,background.width,background.height);
bkCtx.fill();
bkCtx.beginPath();
for(var n=0;n<100;n++){
    var x=parseInt(Math.random()*canvas.width);
    var y=parseInt(Math.random()*canvas.height);
    var radius=Math.random()*3;
    bkCtx.arc(x,y,radius,0,Math.PI*2,false);
    bkCtx.closePath();
}
bkCtx.fillStyle="white";
bkCtx.fill();

// create an new image using the starfield canvas
var img=document.createElement("img");
img.src=background.toDataURL();

您将有两种绘图:

  1. 明星的平移背景
  2. 将绘制游戏对象的前景。
  3. 因此,创建2个相互对齐的画布。背面画布用于游戏对象的星星和前画布。

    这是拍摄星空运动图像的背景画布:

    enter image description here

    这是你的游戏对象去的前景画布 - 看我俗气的“火箭”

    enter image description here

    这些是为了创建背景/前景组合而堆叠的2幅画布:

    enter image description here

    这是用于堆叠2幅画布的Html + CSS:

    <div id="container">
      <canvas id="background" class="subcanvs" width=300; height=300;></canvas>
      <canvas id="canvas" class="subcanvs" width=300; height=300;></canvas>
    </div>
    
    #container{
      position:relative;
      border:1px solid blue;
      width:300px;
      height:300px;
    }
    .subcanvs{
      position:absolute;
    }
    

    以下是如何使用星空图像在背景画布上创建平移星空:

    var fps = 60;
    var offsetLeft=0;
    panStars();
    
    function panStars() {
    
        // increase the left offset
        offsetLeft+=1;
        if(offsetLeft>backImage.width){ offsetLeft=0; }
    
        // draw the starfield image and
        // draw it again to fill the empty space on the right of the first image
        bkCtx.clearRect(0,0,background.width,background.height);
        bkCtx.drawImage(backImage,-offsetLeft,0);
        bkCtx.drawImage(backImage,backImage.width-offsetLeft,0);
    
        setTimeout(function() {
            requestAnimationFrame(panStars);
        }, 1000 / fps);
    }
    

    现在前面的画布用于所有游戏对象。

    您的游戏效率高,性能高,有2幅画布专用于自己的目的。

    这是代码和小提琴:http://jsfiddle.net/m1erickson/5vfVb/

    <!doctype html>
    <html>
    <head>
    <link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
    <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
    
    <style>
    body{padding:20px;}
    #container{
      position:relative;
      border:1px solid blue;
      width:300px;
      height:300px;
    }
    .subcanvs{
      position:absolute;
    }
    </style>
    
    <script>
    $(function(){
    
        // Paul Irish's great RAF shim
        window.requestAnimFrame = (function(callback) {
          return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
          function(callback) {
            window.setTimeout(callback, 1000 / 60);
          };
        })();
    
        var canvas=document.getElementById("canvas");
        var ctx=canvas.getContext("2d");
        var background=document.getElementById("background");
        var bkCtx=background.getContext("2d");
    
        // create an image of random stars
        var backImage=RandomStarsImage();
    
        // draw on the front canvas
        ctx.beginPath();
        ctx.fillStyle="red";
        ctx.rect(75,100,100,50);
        ctx.arc(175,125,25,0,Math.PI*2,false);
        ctx.closePath();
        ctx.fill();
    
        // start panning the random stars image across the background canvas
        var fps = 60;
        var offsetLeft=0;
        panStars();
    
        function panStars() {
    
            // increase the left offset
            offsetLeft+=1;
            if(offsetLeft>backImage.width){ offsetLeft=0; }
    
            // draw the starfield image and draw it again 
            // to fill the empty space on the right of the first image
            bkCtx.clearRect(0,0,background.width,background.height);
            bkCtx.drawImage(backImage,-offsetLeft,0);
            bkCtx.drawImage(backImage,backImage.width-offsetLeft,0);
    
            setTimeout(function() {
                requestAnimFrame(panStars);
            }, 1000 / fps);
        }
    
        function RandomStarsImage(){
    
            // draw a random starfield on the canvas
            bkCtx.beginPath();
            bkCtx.fillStyle="darkblue";
            bkCtx.rect(0,0,background.width,background.height);
            bkCtx.fill();
            bkCtx.beginPath();
            for(var n=0;n<100;n++){
                var x=parseInt(Math.random()*canvas.width);
                var y=parseInt(Math.random()*canvas.height);
                var radius=Math.random()*3;
                bkCtx.arc(x,y,radius,0,Math.PI*2,false);
                bkCtx.closePath();
            }
            bkCtx.fillStyle="white";
            bkCtx.fill();
    
            // create an new image using the starfield canvas
            var img=document.createElement("img");
            img.src=background.toDataURL();
            return(img);
        }
    
    }); // end $(function(){});
    </script>
    
    </head>
    
    <body>
        <div id="container">
          <canvas id="background" class="subcanvs" width=300; height=300;></canvas>
          <canvas id="canvas" class="subcanvs" width=300; height=300;></canvas>
        </div>
    </body>
    </html>