touchesMoved不定期地调用
我正在制作一款iOS游戏,主要是在屏幕上拖动大对象。 当我在实际的iPad / iPhone上运行游戏一段时间(持续在屏幕上拖动对象的圆圈)时,每隔5分钟左右拖动的对象就会全部结束约10-30秒 。 然后,它回到丝绸般光滑。
从表面上看,游戏的帧速率似乎下降到了15fps,但事实上,它一直在以60fps的速度运行。 不过,我注意到唯一不顺畅的是被拖动的对象 ,而游戏的其余部分都运行得非常顺利。
这让我相信口吃与iOS中的触摸input有关。 所以我开始看touchesMoved,看到它通常每16毫秒调用一次(所以触摸input以60 fps运行)。 到现在为止还挺好。
然后我注意到, 当对象开始口吃时,touchesMoved开始以奇怪的时间间隔被调用,在8毫秒和50毫秒之间波动很大。
所以,当触摸屏处于这种奇怪的状态时,有时touchesMoved会在前一次调用后的8毫秒内被调用,有时直到前一次调用后的50毫秒才会被调用。 当然,这使得被拖动的对象看起来全是断断续续的,因为它的位置是以不规则的间隔更新的。
你有什么想法是什么可能造成触摸移动停止被定期调用,如通常一样?
奖金:
– 每当我倾斜屏幕强制屏幕方向改变时,大约70%的时间触摸屏进入上述状态touchesMoved开始被不规则地调用。 然后在10-20秒后恢复正常,再次看起来平滑。
– 我已经在两台iPad和两台iPhone(iOS 6和7)上试过了,这个问题出现在所有这些设备上。
– 使用OpenGLES视图来显示graphics。 它使用CADisplayLink
同步到显示刷新率。
– 我用来testing这个的Xcode项目已经由unity3d游戏开发工具生成,但是我发现了几个非统一的游戏出现了相同的问题。 这似乎是一个全系统的问题。 注意我使用CFAbsoluteTimeGetCurrent
测量objective-c中的CFAbsoluteTimeGetCurrent
,完全在统一之外。
这不是Unity中的一个错误。
操作系统内部的某些东西正在进入不良状态,并且触摸拖动消息停止stream畅地stream动。 有时你会在一个框架中得到多个更新,有时你会得不到任何更新。
这个问题不会发生在iPhone4或以下,或者如果游戏运行在30Hz的帧频。
我在使用我以前在公司工作时编写的内部引擎时遇到了这个错误。 在升级拼字游戏types游戏的UI系统之后,它首先体现出来,在屏幕上拖动图块。 这是非常奇怪的,我从来没有能够确定确切的再现步骤,但他们似乎在某种程度上与时间有关。
“愤怒的小鸟”(除非现在已经修好)以及市面上的其他各种游戏,基本上都是用拖动滚动或移动的东西。 对于愤怒的小鸟,只要进入一个水平,开始横向滚动。 大多数时候,它会丝绸般光滑,但可能是十分之一,这将是笨重的。 重新启动应用程序,然后重试。
解决方法是将input更新频率降低到30Hz几帧。 这会使操作系统的内部不稳定,让它有时间自行摆脱,所以当它回到60Hz时,它会再次平稳运行。
这样做,只要你检测到坏的状态已经input。
我也遇到过这个 我可以validation这是Unity 4.3.x中的一个错误。 我的4.2.x版本在60Hz下使用TouchPhase在每一帧上build立一个触摸点。 我的4.3.x的版本得到20-40Hz与TouchPhase.Stationary丢弃帧发射。
TestFlight历史logging保存了我的理智。
不要忘记用UT提交一个bug。
这真是一场灾难。 有时候是滞后的,有时真的很顺利。 即使GPU和CPU利用率低于10%,它也会滞后。 这不是Unity的bug。 我正在使用cocos2d v3。 如果有人发现治愈,请张贴!
我也遇到过这个。 我目前仍然需要validation的假设是,如果您要求给定的帧速率(例如60fps),但是实际实现的帧速率小于(例如45fps),则会导致定时/竞争条件问题Unity以更高的帧速率请求来自iOS的input,比实际运行的速度更快。 但是,如果将其设置为30fps(至less在使用iOS 9.1的UNITY 5.2testing中),则会得到稳定的30Hzinput。 当我禁用了我的游戏块,它运行在一个非常稳定的60fps,那么我会始终如一地从触摸屏获得60Hz的input。 这是我现在所拥有的,但我必须在一个我还没有时间做的简单的项目中certificate这一点。 希望这可以帮助别人。
我发现这个问题的一个潜在的解决scheme在这里: https : //forums.developer.apple.com/thread/62315 (在这里发布,因为它花了我很多研究,偶然发现该链接,而这个StackOverflow的问题是第一个谷歌的结果)。
为了跟上这一点,我对苹果公司的错误报告有了一个响应。 这是回应:
“只要你不引起任何显示更新,屏幕停留在低功率,因此30赫兹模式,这反过来也保持事件inputstream下降30赫兹。一个解决方法是实际上导致每个接收到的移动显示更新,即使只需要input一个像素的一个像素的移动,而不会触发明确的屏幕更新。
在我的应用程序中,使用GLKView,我将其preferredFramesPerSecond设置为60.偶尔,我的input速率会随机下降到30hz。 苹果的反应并没有完全解释为什么会发生这种情况,但显然,处理这种情况的预期方法是直接从touchesMoved()拖动时调用display()。
我已经subclassed GLKView,并将preferredFramesPerSecond设置为60.在touchesBegan(),我设置isPaused = true,并开始在touchesMoved()内调用display()。 在touchesEnd()上,我设置了isPaused = false。 这样做,我不再有任何问题 – 应用程序比以往任何时候都更高性能。
苹果的例子TouchCanvas.xcodeproj所有绘制内touchesMoved()以及,所以我想这是处理这个意图的方式。
据我所知,实现平滑外观的最佳select可能是在触摸事件之间进行插值,而不是立即将对象映射到触摸位置。
tl; dr:似乎只是有一个CADisplayLink
导致任何 OpenGL上下文或金属设备绘制在60fps可以导致这一点。
我在我的iPhone 7 Plus w / iOS 10.2.1上重新expression了这一点。
我用一个带有preferredFramesPerSecond = 60
的CADisplayLink做了一个小样本简单的应用程序,并尝试了下面的渲染方法:
-
GLKView
w /display()
-
CAEAGLLayer
,按照苹果公司在WWDC的规定使用(不透明,唯一的一层,全屏,没有绘制在上面) -
MTLDevice
在每种情况下,渲染方法只会清除屏幕,而不是尝试绘制其他任何东西。
在每种情况下,我都看到了投入率问题。
下面的“诡计”也似乎什么也不做,当在里面调用touchesMoved
:
- 调用
glkView.setNeedsDisplay()
(enableSetNeedsDisplay
设置为true
) - 移动一些其他的看法
- 调用
glkView.display()
(实际上,它似乎可以将input速率提高到每秒40个事件,但据我所知,看起来并不好,似乎不对,所以我不会推荐它。)
运行所有这些testing后,我放弃了。 相反,我插入我的对象之间的触摸位置,而不是。 所以这也是我的build议。
但我想我会把我的研究包括在内,以防别人刺伤它并find更好的解决scheme。