2013-06-18 233 views
1

我對帆布比較新。在找到我的腳時,我正在創建一個簡單的街機遊戲。帆布:動畫簡單的明星場

我的問題是關於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)和動畫製作者,或者是它更好地利用我上面使用的像素方法。

您的幫助/提前:-)

+0

您遇到的實際性能問題,或者是這個約過早的優化? – bfavaretto

+0

http://gamealchemist.wordpress.com/2013/06/16/introducing-jsparkle-a-versatile-and-fast-javascript-particle-engine/ – GameAlchemist

回答

4

原來的指導非常感謝該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個對齊的畫布。後畫布是爲星星和前畫布爲您的遊戲對象。

這是背景畫布平移星空的運動圖像:

enter image description here

這是前景畫布在您的遊戲對象去 - 看我的俗氣「火箭」

enter image description here

這些是2個畫布堆疊以創建背景/前景組合:

enter image description here

下面是HTML + CSS來堆疊2個畫布:

<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> 
+0

嗨markE。非常感謝你的完美解決方案。即使在寬度/高度加倍時,動畫仍然非常平滑,歡呼聲...... :-) – user2190690

+0

嗨,馬克,我將「代碼」複製到「myDir/soStars.html」文件中。我製作了「myDir/css/reset.css」並複製了http://meyerweb.com/eric/tools/css/reset/中的內容。我雙擊soStars.html並在WinXP sp3的FF 21.0中啓動。結果太空飛船顯示西斯白色背景但是沒有明星領域。我在fireBug中設置了一個斷點「bkCtx.clearRect(0,0,background.width,background.height);」結果星域顯示。我重置斷點,並設置一個在「setTimeout(function(){」。結果沒有明星領域。感謝您的幫助。 - 愛和平, - 喬 –

+0

@ JoeCodeswelluser601770:OOPS!我忘了添加保羅愛爾蘭偉大的請求動畫幀後備通過你的FF)我已經更新了我的答案和小提琴,所以他們現在應該爲你工作感謝您的提醒! – markE