2013-06-18 617 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