Javascript 游戏循环
Posted
技术标签:
【中文标题】Javascript 游戏循环【英文标题】:Javascript Game Loop 【发布时间】:2011-11-13 00:15:53 【问题描述】:我有一些关于 javascript 循环的问题。
问题:
为什么 JavaScript 循环会冻结浏览器 为什么绘制速度很慢,即使它以每 1 毫秒绘制 1 次的速度运行,而且绘制的是最简单的东西! 有什么解决办法? flash 快要死了,我们现在该怎么办?这是你自己尝试的画布代码:
<!doctype html>
<html>
<head>
</head>
<body>
<canvas id="c" ></canvas>
<script type="text/javascript">
var c = document.getElementById( 'c' );
ctx = c.getContext( '2d' );
var x = 100;
ctx.fillStyle= '#f00';
function loop()
ctx.fillRect( x, 100, 20, 20 );
++x;
setInterval( loop, 1 );
</script>
</body>
</html>
【问题讨论】:
你的电脑有多牛?听起来不太强大 @AustinHenley 不过它会被 HTML5 取代,因为它是一个更合适的工具 与本帖相同***.com/questions/25612452/… 不要使用setInterval()
替换为window.requestAnimationFrame()
【参考方案1】:
为什么 JavaScript 循环会冻结浏览器(在 C++ 中不会发生)
JavaScript 是单线程的。 DOM 的状态不能在 javascript 代码运行或竞争条件发生时改变。这意味着没有绘图/回流。
为什么绘图速度很慢,即使它以每 1ms 1 次绘图运行,而且它正在绘制最简单的东西!
它不是以 1 毫秒运行,而是以 10 毫秒运行,因为浏览器不允许您如此紧密地循环。
解决办法是什么? flash快死了,我们现在该怎么办?
使用 requestAnimationFrame 并以 60 FPS 运行游戏,为什么还需要更多?
Example using (webkit) requestAnimationFrame 对我来说运行流畅。
【讨论】:
(webkit/mozilla)RequestAnimationFrame 并不真正与刷新率同步,它只是一个基于刷新率的时间间隔回调。通过这种推算,以两倍的帧速率进行渲染可以看到渲染平滑度的提高,而如果它是完美的定时则不会。问题在于,您在浏览器中找到的 JavaScript 从未被设计为执行我们真正希望在浏览器中执行的高性能多线程任务。这不是 JavaScript 的缺点,只是将 JavaScript 用作浏览器中的单线程事件接收器。 "JavaScript 是单线程的。"不是真的 javascript 是多线程的developer.mozilla.org/en-US/docs/Web/Guide/Performance/…【参考方案2】:一毫秒是一个极短的时间间隔。 时间间隔如此之短,以至于您的代码几乎会一直在 UI 线程中运行,从而导致浏览器无响应。
您需要留出停顿,让用户有时间与页面互动。
使用至少十毫秒的间隔,最好是一百毫秒。
【讨论】:
根本不是这样。 setInterval 不会使浏览器无响应。 @Raynos:当区间中的代码运行时,浏览器没有响应。如果代码没有运行没有任何时间,浏览器将不会响应。 但是浏览器有一个最小设置超时来避免这个确切的问题。这个最小值是 10。这也不是问题。浏览器可以在 10 毫秒内完成大量回流渲染 @Raynos:这是限制标准吗?这是在哪里指定的?我没有意识到这一点。 对于 Firefox 来说似乎是 4 毫秒:mxr.mozilla.org/mozilla-aurora/source/dom/base/…【参考方案3】:帧率下降并最终导致浏览器冻结的原因是由于画布元素占用的内存。我已经回答了这个问题。你可以找到线程here。
每次你在画布上绘制东西时,该操作都会保存到画布的路径中。每次在画布上绘制内容时,此路径会占用更多内存。如果您不清空画布的路径,则会出现帧率下降。例如,查看您的 javascript 与清除画布路径的 javascript 之间的执行时间差异,
var c = document.getElementById( 'c' );
ctx = c.getContext( '2d' );
var x = 100;
ctx.fillStyle= '#f00';
function loop()
ctx.beginPath();
ctx.fillRect( x, 100, 20, 20 );
++x;
setInterval( loop, 1 );
【讨论】:
以上是关于Javascript 游戏循环的主要内容,如果未能解决你的问题,请参考以下文章