Javascript canvase上下文上的ClearRect是否会随着时间的推移降低代码的速度?
我启动代码,在dev窗口中观察,没有错误。图像一开始移动得很快,但几秒钟后,它就变成了一个裂缝 我在这里查过了,但我想不出来。我是新手,所以这可能是问题所在 我试着把它分解成基本的功能步骤,而不是任何类,前后放置“==”和“==”(因为我不知道它们之间的真正区别),并从“setInterval”改为“setTimeout”,以防我调用间隔过快 我非常喜欢Javascript,这是我第一次真正使用canvas HTML代码只是简单地添加脚本,没有其他内容。脚本末尾的窗口加载运行“startgame” 谢谢你能帮我做的一切Javascript canvase上下文上的ClearRect是否会随着时间的推移降低代码的速度?,javascript,performance,canvas,Javascript,Performance,Canvas,我启动代码,在dev窗口中观察,没有错误。图像一开始移动得很快,但几秒钟后,它就变成了一个裂缝 我在这里查过了,但我想不出来。我是新手,所以这可能是问题所在 我试着把它分解成基本的功能步骤,而不是任何类,前后放置“==”和“==”(因为我不知道它们之间的真正区别),并从“setInterval”改为“setTimeout”,以防我调用间隔过快 我非常喜欢Javascript,这是我第一次真正使用canvas HTML代码只是简单地添加脚本,没有其他内容。脚本末尾的窗口加载运行“startgame
var winX=0;
var winY=0;
var scaleX=0;
var scaleY=0;
var bkcolor="#777777";
var ctx;
var objs=[];
var wallimg = new Image();
wallimg.src = 'wall.png';
var willy=new Image();
willy.src='willy.gif';
var player;
var gameActive=0;
var keyboard=[];
function startGame()
{
var i;
setWindow();
theBoard.start();
gameActive=1;
someting=new Obj(0,10,600,20,"PATTERN",wallimg);
someting.setimage(wallimg);
Obj.Wall(40,100,100,16,wallimg);
Obj.Wall(0,420,620,16,wallimg);
Obj.Wall(0,0,16,440,wallimg);Obj.Wall(584,0,16,440,wallimg);
player=new Obj(24,400,16,16,"PLAYER",willy);
player.setimage(willy);
player.gravity=1;
}
function setWindow()
{
winX = window.innerWidth|| document.documentElement.clientWidth|| document.body.clientWidth;
winY = window.innerHeight|| document.documentElement.clientHeight|| document.body.clientHeight;
winX=winX-4;
winY=winY-4;
scaleX=640/winX;
scaleY=480/winY;
if (gameActive==1) {
theBoard.canvas.width = 600/scaleX;
theBoard.canvas.height = 440/scaleY;
theBoard.canvas.style.left=""+20/scaleX+"px";
theBoard.canvas.style.top=""+20/scaleY+"px";
}
}
function setBackdrop(img)
{
var str="<img src='"+img+"' onclick='showCoords(event);' style='";
str=str+"width:"+winX+"px;height:"+winY+"px;'>";
document.getElementById('page').innerHTML=str;
document.getElementById('page').innerHTML=str;
currimage=img;
}
var theBoard = {
canvas : theCanvas=document.createElement("canvas"),
start : function() {
this.canvas.width = 600/scaleX;
this.canvas.height = 440/scaleY;
this.canvas.style.left=""+20/scaleX+"px";
this.canvas.style.top=""+20/scaleY+"px";
this.canvas.style.position="absolute";
this.canvas.tabIndex=1;
this.context = this.canvas.getContext("2d");
ctx=this.context;
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.canvas.style.backgroundColor=bkcolor;
setTimeout(updateGameArea, 40);
window.addEventListener('keydown', function (e) {
e.preventDefault();
keyboard=(keyboard||[]);
keyboard[e.keyCode]=(e.type=="keydown");
})
window.addEventListener('keyup', function (e) {
keyboard[e.keyCode]=(e.type=="keydown");
})
},
stop : function() {
},
restart:function() { this.interval = setTimeout(updateGameArea, 40);},
clear : function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function updateGameArea()
{
var i;
theBoard.clear();
if (keyboard && keyboard[37])
{
player.speed-=2; if (player.speed<-8) player.speed=-8;
}
else if (player.speed<0)
{
player.speed+=1;
}
if (keyboard && keyboard[39])
{
player.speed+=2; if (player.speed>8) player.speed=8;
}
else if (player.speed>0)
{
player.speed-=1;
}
if (player.gravity<1) player.gravity++;
if (keyboard && keyboard[38] && player.gravity>-1 && player.canjump==1){
player.gravity=-16;
player.dir=-6;
player.canjump=0;
}
if (player.gravity<4) {player.gravity=player.gravity+player.dir; player.dir+=4;if (player.dir>16) player.dir=16;}
if (player.gravity!=0)
{
player.y+=player.gravity;
if (checkWalls(player)==true)
{ player.y-=player.gravity;
if (player.gravity>0) player.canjump=1;
}
}
if (player.speed!=0)
{
player.x+=player.speed;
if (checkWalls(player)===true)
player.x-=player.speed;
}
for (i=0;i<objs.length;i++)
objs[i].draw();
setTimeout(updateGameArea, 10);
}
function checkWalls(obj)
{
var i;
for (i=0;i<objs.length;i++)
{
if (objs[i].type=="WALL")
if (obj.collision(objs[i])) {return true;}
}
return false;
}
class Obj {
constructor (x,y,w,h,t,img="") {
this.width=w;
this.height=h;
this.x=x;
this.y=y;
this.type=t;
this.imagemap=img;
this.speed=0;
this.gravity=0;
this.dir=0;
this.canjump=1;
this.pattern=0;
objs[objs.length]=this;
}
static Wall(x,y,w,h,img) {
var id=new Obj(x,y,w,h,"WALL",img);
return id;
}
draw()
{
if ((this.x/scaleX)<0 || (this.x/scaleX)>theBoard.canvas.width ||
(this.y/scaleY)<0 || (this.y/scaleY)>theBoard.canvas.height)
return;
switch (this.type){
case 'PATTERN':
case 'WALL':
{
if (this.pattern===0)
{ this.pattern=ctx.createPattern(this.imagemap,"repeat");}
ctx.rect(this.x/scaleX,this.y/scaleY,this.width/scaleX,this.height/scaleY);
ctx.fillStyle=this.pattern;
ctx.fill();
break;
}
case 'PLAYER':
ctx.drawImage(this.imagemap,0,0,this.width,this.height,this.x/scaleX,this.y/scaleY,this.width/scaleX,this.height/scaleY);
break;
}
}
setimage(img)
{
this.imagemap=img;
}
collision(wth) {
if (((this.x+this.width)>wth.x) && (this.x<(wth.x+wth.width))
&& ((this.y+this.height)>wth.y) && (this.y<(wth.y+wth.height)))
{return true;}
else return false;
}
}
window.onload=startGame();
var-winX=0;
var-winY=0;
var-scaleX=0;
var-scaleY=0;
var bkcolor=“#777777”;
var-ctx;
var objs=[];
var wallimg=新图像();
wallimg.src='wall.png';
var willy=新图像();
willy.src='willy.gif';
var播放器;
var gameActive=0;
var键盘=[];
函数startName()
{
var i;
setWindow();
theBoard.start();
配子活性=1;
someting=新Obj(0,10600,20,“模式”,瓦利姆);
设置图像(wallimg);
目标墙(40100100,16,墙);
目标墙(0420620,16,墙);
目标墙(0,0,16440,瓦利姆);目标墙(584,0,16440,瓦利姆);
玩家=新的Obj(24400,16,16,“玩家”,威利);
player.setimage(威利);
玩家。重力=1;
}
函数setWindow()
{
winX=window.innerWidth | | document.documentElement.clientWidth | | document.body.clientWidth;
winY=window.innerHeight | | | document.documentElement.clientHeight | | | document.body.clientHeight;
winX=winX-4;
winY=winY-4;
scaleX=640/winX;
斯卡利=480/温妮;
如果(gameActive==1){
theBoard.canvas.width=600/scaleX;
theBoard.canvas.height=440/scaleY;
theBoard.canvas.style.left=”“+20/scaleX+“px”;
theBoard.canvas.style.top=”“+20/scaleY+“px”;
}
}
功能设置下降(img)
{
var str=“”;
document.getElementById('page')。innerHTML=str;
document.getElementById('page')。innerHTML=str;
currimage=img;
}
var theBoard={
canvas:theCanvas=document.createElement(“canvas”),
开始:函数(){
this.canvas.width=600/scaleX;
this.canvas.height=440/scaleY;
this.canvas.style.left=”“+20/scaleX+“px”;
this.canvas.style.top=”“+20/scaleY+“px”;
this.canvas.style.position=“绝对”;
this.canvas.tabIndex=1;
this.context=this.canvas.getContext(“2d”);
ctx=this.context;
document.body.insertBefore(this.canvas,document.body.childNodes[0]);
this.canvas.style.backgroundColor=bkcolor;
setTimeout(updateGameArea,40);
window.addEventListener('keydown',函数(e){
e、 预防默认值();
键盘=(键盘| |[]);
键盘[e.keyCode]=(e.type==“keydown”);
})
window.addEventListener('keyup',函数(e){
键盘[e.keyCode]=(e.type==“keydown”);
})
},
停止:函数(){
},
restart:function(){this.interval=setTimeout(updateGameArea,40);},
清除:函数(){
this.context.clearRect(0,0,this.canvas.width,this.canvas.height);
}
}
函数updateGameArea()
{
var i;
黑板。清除();
如果(键盘和键盘[37])
{
player.speed-=2;如果(player.speed0)
{
速度-=1;
}
如果(player.gravity-1&&player.canjump==1){
重力=-16;
player.dir=-6;
player.canjump=0;
}
如果(player.gravity16)player.dir=16;}
如果(玩家重力!=0)
{
player.y+=player.gravity;
如果(检查墙(玩家)=真)
{player.y-=player.gravity;
如果(player.gravity>0)player.canjump=1;
}
}
如果(玩家速度!=0)
{
player.x+=player.speed;
如果(检查墙(玩家)==true)
player.x-=player.speed;
}
对于@kaido指出的(i=0;i),您的问题的解决方案如下:
简而言之,只需将主循环代码放在beginPath
和closePath
之间,而无需更改theBoard.clear()方法
function updateGameArea()
{
var i;
theBoard.clear();
theBoard.context.beginPath();
...
theBoard.context.closePath();
requestAnimationFrame(updateGameArea);
}
我最初写的答案是:
重置维度以清除画布在您的情况下效果更好,但会导致性能问题。
clear : function() {
this.context.canvas.width = 600 / scaleX;
this.context.canvas.height = 440 / scaleY;
}
另外,使用requestAnimationFrame
,因为它可以消除使用setTimeout
时可能发生的任何闪烁
requestAnimationFrame(updateGameArea);
以下是一个猜测。我认为您的周期已经用完,并且您的帧正在相互叠加。乍一看,我在您的代码中没有看到任何会导致内存泄漏的内容。除非您查看控制台内存图并发现确实如此,因为您正在反复添加侦听器或类似的内容。但只需c学习画布不会减慢速度,它基本上与在数组中设置一组值相同
但是:如果CPU无法在下一个操作进入队列之前完成一个操作,则在setTimeout()内运行繁重的画布操作可能会对CPU造成很大的负担。请记住,超时是异步的。如果CPU节流,并且指定的刷新率(40毫秒)如果时间太短,则会留下一整堆重绘和清除,这些重绘和清除在最后一次之后等待执行,而不会给CPU任何喘息的时间
大多数Canvas动画包都有处理此问题的方法,不仅设置超时,还可以在触发调用堆栈中的下一个帧之前等待确保最后一次重画完成,并在必要时删除一帧。在进行重画之前,至少要设置一个全局变量,如\u redrawing=true
nd然后在重画完成时将其设置为false,并在其仍然为true时忽略对setTimeout的任何调用。这将让您计算可能要丢弃的帧数。如果您看到此数字随着时间的推移而增加,您的CPU