touchesMoved以不规则的间隔调用

时间:2014-01-20 19:11:56

标签: ios cocoa-touch unity3d timing touchesmoved

我正在制作一款适用于iOS的游戏,您可以在屏幕上拖动大对象。当我在一台真正的iPad / iPhone上运行游戏一段时间(每隔5分钟左右在屏幕上连续拖动物体)时,拖动的物体会在10到30秒左右的时间内全部结束。然后,它回到移动丝般光滑。

从视觉上看,游戏的帧速率似乎暂时降至15 fps,但事实上它一直以低至60 fps的速度运行。但是,我注意到唯一没有顺利移动的是被拖动的对象,而游戏的其余部分都运行得非常流畅。

这让我相信口吃与iOS中的触控输入有关。所以我开始查看touchesMoved,并且看到它通常每16毫秒调用一次(因此触摸输入以60 fps运行)。到目前为止一切都很好。

然后我注意到当对象开始出现口吃时,touchesMoved开始以奇怪的时间间隔被调用,在8毫秒到50毫秒之间波动。

因此,当触摸屏处于这种奇怪的状态时,有时touchesMoved将在前一次调用后的8毫秒内被调用,有时它会在前一次调用后50毫秒被调用。当然,这会使拖动的对象看起来很不稳定,因为它的位置会以不规则的间隔更新。

您是否知道可能导致touchesMoved停止定期调用的原因是什么?


加成:

- 每当我倾斜屏幕以强制屏幕方向改变时,大约70%的时间触摸屏进入上述状态,其中touchesMoved开始被不规则地调用。然后在10-20秒后它恢复正常,一切看起来都很光滑。

- 我已经在两台iPad和两台iPhone上试用了这款产品,iOS 6和7,所有这些设备都出现了这个问题。

- OpenGLES视图用于显示图形。它使用CADisplayLink与显示刷新率同步。

- 我用来测试这个的Xcode项目是由unity3d游戏开发工具生成的,但是我发现了几个出现相同问题的非统一游戏。这似乎是一个系统范围的问题。注意我使用CFAbsoluteTimeGetCurrent来衡量objective-c中的时间,完全不在统一之外。

6 个答案:

答案 0 :(得分:3)

这不是Unity中的错误。

操作系统内部的某些东西进入了不良状态,触摸拖动消息停止流畅。有时您会在一个框架中获得多个更新,有时您将无法获得任何更新。

iPhone4或更低版本不会发生此问题,或者游戏以30Hz的帧速率运行。

我在使用我在以前的公司工作时写的内部引擎时遇到了这个错误。它首先在升级拼字游戏类型游戏的UI系统后显现出来,您可以在屏幕上拖动磁贴。这完全是奇怪的,我无法确定准确的再现步骤,但它们似乎与时间有关,不知何故。

它也可以在愤怒的小鸟(除非他们现在已经修复它)以及市场上的各种其他游戏中看到,基本上任何都有触摸拖动滚动或移动。对于愤怒的小鸟,只需进入一个级别并开始向侧面滚动。大多数时候它会如丝般顺滑,但也许十分之一,它会很笨重。重新启动应用并重试。

解决方法是将输入更新频率降低到30Hz几帧。这会以某种方式震动操作系统的内部结构,让它有时间将自己拉直,所以当你将其恢复到60Hz时,它会再次平稳运行。

每当您检测到输入了错误状态时,请执行此操作。

答案 1 :(得分:0)

我也遇到过这种情况。我可以验证它是Unity 4.3.x中的一个错误。 我的4.2.x使用TouchPhase.Moved在每帧上以60Hz建立过程触摸设备。 我的4.3.x版本使用TouchPhase获得20-40Hz。在丢帧上发射。预定。

TestFlight历史在这里保存了我的理智。

不要忘记向UT提交错误。

答案 2 :(得分:0)

这是一场真正的灾难。有时它会滞后,有时它会非常顺畅。即使GPU和CPU利用率低于10%,它也会滞后。它不是Unity的bug。我使用的是cocos2d v3。 如果有人找到治疗方法,请发布!

答案 3 :(得分:0)

我也遇到过这种情况。我目前的假设仍然需要验证,如果你要求给定的帧速率(例如60fps),但实际实现的帧速率小于(例如45fps),这会导致时间/竞争条件问题Unity以比实际运行时更高的帧速率请求来自iOS的输入。但是,如果将其设置为30fps(至少在我使用iOS 9.1的UNity 5.2测试中),那么您将获得稳定的30Hz输入。当我禁用了我的一大块游戏并且它以非常稳定的60fps运行时,我将始终从触摸屏获得60Hz的输入。这就是我现在所拥有的,但我必须在一个我没有时间去做的简单项目中证明这一点。希望这有助于其他人。

答案 4 :(得分:0)

我在这里找到了一个解决这个问题的潜在解决方案:https://forums.developer.apple.com/thread/62315(在这里发帖是因为我花了很多时间研究这个链接,而这个StackOverflow问题是谷歌的第一个结果)。

  

为了跟进这一点,我对Apple的错误报告产生了共鸣。这个   是回应:

     

“只要您不进行任何显示更新,屏幕就会保留   低功率,因此30hz模式,这反过来也保持事件   输入流量为30赫兹。解决方法是实际导致   显示每个接收到的移动的更新,即使它只是一个像素   如果需要输入而没有明确的屏幕更新,则移动视图   被触发。“

     

在我的应用程序中,使用GLKView,我设置了它   preferredFramesPerSecond to 60.偶尔,我的输入率会   随机下降到30hz。 Apple的回应并未完全解释   为什么会这样,但显然是预期的处理方法   这是在拖动时直接从touchesMoved()调用display()。

     

我已将GLKView子类化,并将preferredFramesPerSecond设置为60. On   touchesBegan(),我设置isPaused = true,并开始调用display()   在touchesMoved()中。在touchesEnd()上,我设置了isPaused = false。干   这个,我不再有任何问题 - 该应用程序更高效   比以往任何时候都好。

     

Apple的示例TouchCanvas.xcodeproj从内部完成所有绘图   touchesMoved()也是如此,所以我想这是预期的处理方式   此

答案 5 :(得分:0)

据我所知,实现平滑外观的最佳选择可能是在触摸事件之间进行插值,而不是立即将对象映射到触摸位置。

tl; dr:似乎只有一个CADisplayLink导致任何 OpenGL上下文以60fps绘制的金属设备会导致这种情况。

我在iOS 7.2.1的iPhone 7 Plus上重复了这个。

我使用带有preferredFramesPerSecond = 60的CADisplayLink制作了一个小样本简单应用,并尝试了以下渲染方法:

  1. GLKView w / display()
  2. CAEAGLLayer,按照Apple at WWDC的规定使用(不透明,单层,全屏,上面没有任何内容)
  3. MTLDevice
  4. 在每种情况下,渲染方法只会 清除屏幕,而不是尝试绘制任何其他内容。

    在每种情况下,我都看到了输入速率问题。

    touchesMoved内部调用时,以下“技巧”似乎也无效:

    1. 致电glkView.setNeedsDisplay()enableSetNeedsDisplay设置为true
    2. 移动其他视图
    3. 调用glkView.display()(实际上,似乎它可以将您的输入速率提高到每秒40个事件。但就我所知,它看起来不会更好,而且似乎做错了,所以我不推荐它。)
    4. 在完成所有这些测试后我放弃了。相反,我在触摸位置之间插入我的对象。所以这也是我推荐的。

      但是我想我会把我的研究包括在这里以防其他人对它进行研究并找到更好的解决方案。