问题描述
我对Canvas比较陌生。找到我的脚我正在创建一个简单的街机游戏。
我的问题是关于CPU性能/效率。
使用requestAnimationFrame我正在调用以下函数:
bgAnimateId = requestAnimationFrame(scrollBg);
函数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 divs)和动画,或者更好地利用我上面使用过的像素方法。
非常感谢您的帮助/指导:-)
事实证明 context.getImageData
和 context.putImageData
执行起来非常昂贵并且有100幅画布太多。
所以这是一个创建高效平移星空的计划:
使用 context.drawImage
非常高效,执行起来并不是很昂贵。
以下是如何在画布上绘制随机星空,然后将该画布保存为图像:
//在画布上绘制一个随机星空
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();
//使用星空画布创建一个新图像
var img = document.createElement(img);
img.src = background.toDataURL();
您将有2种绘图:
- 明星的平移背景
- 将绘制游戏对象的前景。
因此,创建2个相互对齐的画布。后面的画布用于游戏对象的星星和前画布。
这是一个平移星域运动图像的背景画布:
这是你的游戏对象去的前景画布 - 看我俗气的火箭
这些是用于创建背景/前景组合的2个画布:
这是用于堆叠2幅画布的Html + CSS:
< div id =容器>
< canvas id =backgroundclass =subcanvswidth = 300;高度= 300;>< /画布>
< canvas id =canvasclass =subcanvswidth = 300;高度= 300;>< /画布>
< / div>
#container {
position:relative;
边框:1px纯蓝色;
宽度:300px;
身高:300px;
}
.subcanvs {
position:absolute;
}
以下是如何使用星空图像在背景画布上创建平移星空:
var fps = 60;
var offsetLeft = 0;
panStars();
函数panStars(){
//增加左偏移量
offsetLeft + = 1;
if(offsetLeft> backImage.width){offsetLeft = 0; }
//绘制星空图像和
//再次绘制它以填充第一张图像右侧的空白空间
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张专用于自己目的的画布。
这是代码和小提琴:
<!doctype html>
< html>
< head>
< link rel =stylesheettype =text / cssmedia =allhref =css / reset.css/> < ;! - reset css - >
< script type =text / javascriptsrc =http://code.jquery.com/jquery.min.js>< / script>
< style>
body {padding:20px;}
#container {
position:relative;
边框:1px纯蓝色;
宽度:300px;
身高: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);
//创建随机星星的图像
var backImage = RandomStarsImage ();
//在前画布上绘制
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();
//开始淘选r andom在背景画布上的星星图像
var fps = 60;
var offsetLeft = 0;
panStars();
函数panStars(){
//增加左偏移量
offsetLeft + = 1;
if(offsetLeft> backImage.width){offsetLeft = 0; }
//绘制星空图像并再次绘制
//填充第一张图像右侧的空白区域
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);
}
函数RandomStarsImage(){
//在画布上绘制一个随机星空
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();
//使用星空画布创建一个新图像
var img = document.createElement(img);
img.src = background.toDataURL();
return(img);
}
}); // end $(function(){});
< / script>
< / head>
< body>
< div id =container>
< canvas id =backgroundclass =subcanvswidth = 300;高度= 300;>< /画布>
< canvas id =canvasclass =subcanvswidth = 300;高度= 300;>< /画布>
< / div>
< / body>
< / html>
I'm relatively new to Canvas. In finding my feet I'm creating a simple arcade game.
My question is regarding CPU performance / efficiency.
I'm creating 100 randomly positioned white dots as stars on a black background. On each requestAnimationFrame, the stars move one pixel to the left and as they get to the extreme left that column of pixels is placed on the extreme right of the screen.
Using requestAnimationFrame I'm calling the following function:
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 );
}
My concern is - would it be better to create 100 small canvas elements (or 100 divs) and animate those, or is it better to utilise the pixel methods that I've used above.
Many thanks for your help / guidance in advance :-)
It turns out that context.getImageData
and context.putImageData
are very expensive to perform and having 100 canvases is too many.
So here’s a plan for creating an efficient panning starfield:
Using context.drawImage
is very efficient and not very expensive to perform.
Here’s how to draw a random starfield on a canvas and then save that canvas as an image:
// 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();
You will have 2 kinds of drawing going on:
- A panning background of stars
- A foreground where your game objects will be drawn.
So create 2 canvases aligned on top of each other. The back canvas is for the stars and the front canvas for you game objects.
This is the background canvas that pans the moving image of the starfield:
This is the foreground canvas where your game objects go -- see my cheesy "rocket"
These are the 2 canvases stacked to create a background/foreground combination:
Here is the Html+CSS to stack the 2 canvases:
<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;
}
Here’s how to use the starfield image to create a panning starfield on 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() {
requestAnimationFrame(panStars);
}, 1000 / fps);
}
Now the front canvas is used for all your game objects.
Your game is efficient and performant with 2 canvases dedicated to their own purposes.
Here is code and a Fiddle: 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>
这篇关于画布:动画一个简单的星场的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!