我正在开发一个模拟引力的javascript游戏.它使用HTML5 canvas元素为行星绘制2D椭圆.我在谷歌浏览器中测试我的游戏.这是游戏的链接:http://gravitygame.hostingsiteforfree.com/index.php?page = playHTML
直到5月24日,它工作得很好.但是,Chrome从26.0.1410.64升级到27.0.1453.94后,有时不会绘制填充的椭圆.每次我加载游戏时都不会发生这种情况,而且我在本地运行时从未让它破坏.
这是游戏工作的截图:
这是一个截图,显示它没有填充省略号:
我不知道发生了什么.我将包括绘制所有行星的循环部分.为了便于阅读,我修改了它.
var i = bodies.length; while(i--){ var I = bodies[i]; var planetRad = (I.width/2)*_scale; if(_showTrails){ //draw the planet's trail } if(//the planet is completely off the screen){ //draw a red planet on the edge of the screen ctx.beginPath(); ctx.arc(nX, nY, 2.5, 0, TWOPI); ctx.fillStyle = offScreenColor; ctx.fill(); ctx.strokeStyle = offScreenOutline; ctx.stroke(); } else{ //draw planet ctx.beginPath(); ctx.arc(nX, nY, (I.width/2)*_scale, 0, TWOPI); ctx.closePath(); ctx.fillStyle = I.bodyColor; ctx.fill(); } if(_showMotionVector){ //draw a line from the center of a planet showing the direction and speed it's travelling ctx.strokeStyle = motionColor; ctx.beginPath(); ctx.moveTo(I.getScX(), I.getScY()); ctx.lineTo(I.motion.x * _scale * 12 + I.getScX(), I.motion.y * _scale * 12 + I.getScY()); ctx.stroke(); } }
为什么它偶尔会突然断裂?
我看了一下你的在线代码,发现你正在使用setInterval
动画循环.
这很可能是因为代码无法完成调用计算等等.您冒着堆叠调用的风险 - 对于上下文而言,这意味着您可以拥有相互重置的路径.
首先尝试替换setInterval
用setTimeout
.你当然需要从代码中再次重新触发它 - 更好的是,在函数结尾处将所有内容放入一个带有setTimeout的函数中,即:
function animate() { //... calcs and redraws which you have in setInterval setTimeout(animate, 0); } animate();
我在这里使用0表示超时.setTimeout/setInterval
在任何情况下都不会同步到屏幕刷新率.
如果有效,那你就知道原因了.下一步将是替换它requestAnimationFrame
,但让我知道它是怎么回事.
为了说明问题,我们可以看一下这个例子:
每个块表示循环内的函数,一个循环是一种颜色.请记住,setInterval
在调用相对于调用时,以固定间隔setTimeout
调用.在此示例中,函数在时间预算内执行,因此一切顺利.
在下一个插图中:
支出超出预算,因此setInterval
再次调用,并在第一个完成之前排队等待第二个循环.当在调用之间处理队列时,您最终冒着在"同一时间"处理上下文的两个函数的风险(或者以与您预期的顺序不同的顺序).
Javascript当然是单线程的,因此它们不会同时执行,但是一个等待 - 如果在最后一个块有时间被调用之前调用下一个队列的第一个块,那么第一个块将修改上下文甚至可能在调用上次调用的最后一次调用之前更改路径.随着时间的推移,滞后将会增加并且潜在地(除非一些额外的可用处理资源现在解决队列,然后 - 在繁忙的系统上这不太可能发生)随着更多堆叠发生而变得越来越糟.
即,在这种情况下,您可以beginPath()
在arc
填充之前将行添加到上下文中.
(希望有任何意义......)
使用setTimeout
将阻止此操作,因为它将在动画循环中的所有调用都返回之前不会执行.更好的选择是使用,requestAnimationFrame
因为这将尽可能与屏幕刷新率同步调用.它更低级,因此也更有效率.
另一条路径(没有双关语)是使用Web工作者进行计算.这将是多线程的,并且可以提高整体性能,因为Web工作者不会影响UI线程.