【问题标题】:KeyDown/KeyUp 70-120ms delay. How to reduce?KeyDown/KeyUp 70-120ms 延迟。如何减少?
【发布时间】:2012-06-14 10:51:28
【问题描述】:

我们正在使用画布开发街机(大量动作和速度)浏览器 2d 游戏。

有时我们的测试播放器会向我们报告存在延迟:在键控后播放器仍在移动 5-10 像素。

我已经挖掘了这个问题,你可以看到自己延迟http://jsfiddle.net/C4ev3/7/(尽可能快地尝试 keydown/up any key)。我的结果是从 70 到 120 毫秒。我认为这很多。 (仅供参考,我们的网络延迟为 10-20 毫秒)。

任何想法如何减少这种延迟?

upd 我注意到在好的硬件上这个延迟低于 30-40 毫秒。但我正在 core2duo、winxp、chrome 19 上进行测试——它不是带有 IE6 的 P4 :)

【问题讨论】:

  • 无论如何我们可以看到更多的代码?我怀疑它是导致问题的关键事件。它甚至可能与使用 jQuery 创建速度很重要的游戏有关。如果是客户端,网络延迟也不会影响游戏。
  • 如果我无限按下按键,我有 25-33
  • 但是没有检测到我的向下/向上箭头...
  • 我最少需要 24-32 毫秒。真的,我不能更快地按空格键。
  • 我知道,但我通过快速将其保持在 16 毫秒来进行管理,在正常游戏前大约为 54 毫秒,但除了更新控制台中的值之外,没有其他任何事情会导致延迟(什么是?半毫秒?)您应该发布带​​有您使用的画布重绘的代码,以便我们可以看到阻塞在哪里......我认为是您的画布重绘导致延迟。

标签: javascript canvas keyboard keyboard-events


【解决方案1】:

您可以做的一件事是尝试使用已定义的函数,而不是使用匿名函数,

http://jsfiddle.net/C4ev3/10/ - 对我来说这是在 50-100 MS 时报告的

但是我不推荐 jQuery 用于 Canvas 应用程序,它对于你使用的很少的人来说非常大,你应该尝试使用原生 Javascript

http://jsfiddle.net/C4ev3/11/ - 对我来说这报告了 30-70 MS

Javascript 线程 我在 cmets Javascript 中注意到的一件事不是 Multi-Threaded Well Urm-Arr, 它有点是setInterval是异步而不是同步,但是影响窗口是单线程EG如果你有一个有一些数字的类是它使用setInteval将使用另一个线程并且没有问题但是在任务中改变数学然后需要在页面上进行Draw才会进入底部的JS句柄阙,

Javascript 的某些部分位于不同的线程上,如果您的线程想要更​​改表单,您必须调用主线程来完成更改页面的任何操作都必须像任何 Windows 应用程序一样在主线程上运行你

然而,它不像其他任何东西一样多线程,你不能在给定的 Wim(如 windows)上处理或中止,

其他异步任务包括 AJAX 可以选择异步和同步

更新显示我对 FPS 限制的评论:

请多多包涵。这是链接到一个已经为显示示例而构建的项目: 所以我的游戏完全是 OOP

var elem = document.getElementById('myCanvas');
var context = elem.getContext("2d");
context.fillStyle   = '#888';
context.lineWidth   = 4;
// Draw some rectangles.
context.fillRect(0,   0, 800, 600);
context.fillStyle = '#f00';

var ball = new Ball();
var leftPadel = new Padel(10, 60, 40, 120);
var rightPadel = new Padel(750, 520, 40, 120);

pong = new Pong();
pong.draw();

setTimeout("ball.move()", pong.redrawTime());

在我的 pong 课程中,游戏的所有主要工作都在其中,但这里是您需要查看的 FPS 位

this.fps = 30;
this.maxFPS = 60;

this.redrawTime = function(){
    return (1000 / this.fps)
}

this.lastDraw = (new Date)*1 - 1;

然后你可以看到我的 Interval 在 ball.move 这会在重绘结束时再次调用主 pong 类,我有 FPS 检查和限制代码

this.fps = ((now=new Date) - this.lastDraw);
if(this.fps > this.maxFPS){
    this.fps = this.maxFPS;
}
this.lastDraw = (new Date)*1 - 1;
if(this.reporting = true){
    console.clear();
    console.log("FPS: "+this.fps.toFixed(1))
}
setTimeout("ball.move()", pong.redrawTime());

这会迫使您在不排队主线程的情况下获得最佳 FPS

【讨论】:

  • 嗯,我在发布问题几分钟后用原生 js 代码更新了问题。我有同样的结果。
  • 你在画布上画得怎么样?我曾与 Canvas abit 一起教我自己构建的乒乓球,而你能做的最好的事情之一就是拥有一个 FPS Monitor 和一个 setTimeout 来匹配你的 FPS 这将防止绘图项目的 quing 可能是你的根本原因让我挖出我的乒乓球比赛,看看我可以给你看
  • 我已经更新了我的答案以尝试反映 FPS 绘制速率限制器,为什么这取决于您将事件绑定到页面的事实,因此如果您有 30 个绘制请求,则按下键30 个绘制事件发生在绘制按键按下事件更改之前
  • 使用workers你有真正的线程,但不能访问窗口对象,使用setinterval你也可以创建一个线程,但也不能访问“window”对象来防止排队。这一切都取决于重绘整个画布需要多长时间才能造成阻塞……工人是朝着正确方向迈出的一步,但我仍然在拼命地等待真正的线程,因为不同线程可能对 dom 进行多种更改。 .. 一个八核 cpu 和一个浏览器就这么多... ;-)
  • 你永远不会得到你的“真正的线程”,这个简单的事实是不可能像 Windows 应用程序一样同时更新 DOM 你不能向图形卡发送多个绘图你会得到与您在当前代码库中遇到的相同的错误,您最终会在所请求的内容后面绘制屏幕,​​具有所有线程支持的 Windows 应用程序不能只是重绘屏幕的不同部分,因此为什么您必须使用在主线程上调用,以便只有该线程可以绘制,然后再向 Menny 应用程序绘制导致图形滞后
【解决方案2】:

试试这个:

e.stopPropagation()

停止将事件冒泡到父元素,防止任何 父处理程序不会收到事件通知。

e.preventDefault()

阻止浏览器执行默认操作。使用方法 isDefaultPrevented 知道是否曾经调用过这个方法(在 那个事件对象)。

我的分钟。谷歌浏览器的结果:7ms

【讨论】:

    猜你喜欢
    • 2012-08-10
    • 1970-01-01
    • 1970-01-01
    • 2018-04-10
    • 2012-06-25
    • 2014-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多