javascript - 以每秒 60 次以上的速度渲染画布?
问题描述
我的 JS 代码:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var mouse = {x:0,y:0}
const times = [];
let fps;
function refreshLoop() {
window.requestAnimationFrame(() => {
const now = performance.now();
while (times.length > 0 && times[0] <= now - 1000) {
times.shift();
}
times.push(now);
fps = times.length;
refreshLoop();
});
}
refreshLoop();
function draw() {
ctx.fillStyle = "black"
ctx.fillRect(0, 0, c.width, c.height);
ctx.strokeStyle = "white"
ctx.beginPath();
var e = window.event;
ctx.arc(mouse.x, mouse.y, 40, 0, 2*Math.PI);
ctx.stroke();
ctx.font = "30px Comic Sans MS";
ctx.fillStyle = "red";
ctx.textAlign = "center";
ctx.fillText(fps, c.width/2, c.height/2);
}
setInterval(draw, 0);
document.addEventListener('mousemove', function(event){
mouse = { x: event.clientX, y: event.clientY }
})
我的 HTML 只是画布声明。
据我了解, setinterval(x, 0) 应该尽可能快地运行,但它永远不会超过 60fps。我正在尝试达到 240+ fps 以减少输入延迟。
解决方案
首先,永远不要使用setInterval(fn, lessThan10)
. 很有可能fn
会花费超过这个时间来执行,并且您最终可能会fn
毫无间隔地堆叠大量调用,这可能会导致*与众所周知的while(true)
浏览器 crasher® 相同。
*好吧,在正确的实现中,这不应该发生,但你知道......
现在,对于你的问题...
你的代码是相当有缺陷的。
您实际上正在同时运行两个不同的循环,它们不会以相同的时间间隔被调用。
- 您正在检查requestAnimationFrame循环中的fps,该循环将设置为与浏览器的绘制速率相同的频率(通常为 60*fps*)。
- 你正在绘制你的两个循环没有链接,因此,你在第一个循环中测量的不是你被调用
setInterval(fn, 0)
的速率。draw
有点像如果你这样做了
setInterval(checkRate, 16.6);
setInterval(thefuncIWantToMeasure, 0);
显然,您checkRate
不会thefuncIWantToMeasure
正确测量
所以只是为了表明一个setTimeout(fn, 0)
循环将以更高的速率触发:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var mouse = {
x: 0,
y: 0
}
const times = [];
let fps;
draw();
function draw() {
const now = performance.now();
while (times.length > 0 && times[0] <= now - 1000) {
times.shift();
}
times.push(now);
fps = times.length;
ctx.fillStyle = "black"
ctx.fillRect(0, 0, c.width, c.height);
ctx.strokeStyle = "white"
ctx.beginPath();
ctx.arc(mouse.x, mouse.y, 40, 0, 2 * Math.PI);
ctx.stroke();
ctx.font = "30px Comic Sans MS";
ctx.fillStyle = "red";
ctx.textAlign = "center";
ctx.fillText(fps, c.width / 2, c.height / 2);
setTimeout(draw, 0);
}
<canvas id="myCanvas"></canvas>
现在,即使嵌套setTimeout
循环比 更好setInterval
,您所做的也是视觉动画。
以比浏览器的绘制速度更快的速度绘制此视觉动画是没有意义的,因为您将在此画布上绘制的内容不会绘制到屏幕上。
如前所述,这正是requestAnimationFrame
循环触发的速率。所以对你所有的视觉动画都使用这个方法(至少如果它必须被绘制到屏幕上,在极少数情况下,如果需要,我可以在评论中将你链接到其他方法)。
现在要解决您的实际问题,不是以更高的速率渲染,而是以这样的速率处理用户的输入,那么解决方案是拆分您的代码。
- 保持您的绘图部分绑定到 requestAnimationFrame 循环,不需要变得更快。
- 更新应该从用户输入同步响应用户手势的对象值。不过,请注意某些用户的手势实际上会以非常高的速率触发(例如 WheelEvent 或窗口的调整大小事件)。通常,您不需要获取此类事件的所有值,因此您可能希望将它们绑定到 rAF 节流器中。
- 如果您需要对移动对象进行碰撞检测,则执行将从用户手势内部更新移动对象的数学运算,但不要在屏幕上绘制它。
推荐阅读
- rest - Create an api using lumen and neo4j
- c# - 保护价值与数据的方法?
- javascript - 异步等待默认行为
- javascript - 如何在 vue js 中重用 es6 类?
- ios - 无法存储 Firebase 数据类型“AuthService”没有成员“setUserinformation”
- google-cloud-platform - GKE - 到 VPN 网络的 Kube-DNS 解析
- python - 如何使我的多个 if 语句起作用?或者最好如何在我的代码中使用嵌套循环
- php - Imagen、HEX 到 Byte 和 Byte 到 HEX 并显示 img。Visual Basic 到 PHP
- r - 如何在每个元素前面附加列号?
- haskell - 尝试使用 if 跟踪函数