2

私はキャンバスに比較的慣れていません。私の足を見つけるには、単純なアーケード ゲームを作成しています。

私の質問は、CPU のパフォーマンス/効率に関するものです。

黒い背景に星としてランダムに配置された100個の白い点を作成しています。requestAnimationFrame ごとに、星は 1 ピクセル左に移動し、左端に移動すると、そのピクセルの列が画面の右端に配置されます。

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) を作成してそれらをアニメーション化する方がよいでしょうか、それとも上記で使用したピクセル メソッドを利用する方がよいでしょうか。

事前にあなたの助け/指導に感謝します:-)

4

1 に答える 1

6

とを実行する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();

2 種類の描画が行われます。

  1. 星のパン背景
  2. ゲーム オブジェクトが描画される前景。

そのため、2 つのキャンバスを重ね合わせて作成します。背面のキャンバスは星用で、前面のキャンバスはゲーム オブジェクト用です。

これは、スターフィールドの動画をパンする背景キャンバスです。

ここに画像の説明を入力

これは、ゲーム オブジェクトが移動するフォアグラウンド キャンバスです。安っぽい「ロケット」をご覧ください

ここに画像の説明を入力

これらは、背景と前景の組み合わせを作成するために積み重ねられた 2 つのキャンバスです。

ここに画像の説明を入力

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>
于 2013-06-18T17:14:40.627 に答える