关于滚屏类小游戏帧数抖动的个人解决方法(补充:想了想,其实跟 dt * speed 没区别 …)

有必要贴一下,我的项目所遇到的问题:
小游戏在 Android 上很流畅,但在 iOS 上就比较卡。
因为 2.1.0 有说提升了渲染性能,所以我是升级到了 2.1.0 的。

屏幕滚动类的游戏,是要么移动摄像机、要么移动图片的游戏,类似打飞机这种。
但是论坛内有部分同学遇到了 update 函数的 dt 参数数值波动大,导致游戏卡顿的现象
(相关帖子:update dt 数值波动太大了)。

滚屏,由于我们都是用生命周期回调函数:update 来驱动的,它逐帧回调。
而我们一般也是把配置好的速度值(iSpeed)逐帧计算给图片来实现移动的。
当 update 函数的调用频率本身就不稳定的时候,图片的移动也就不可避免的发生卡顿了。

当然,不稳定的原因也可能是其他因素引起的
(比如论坛首席客服王哲大大说的:不止是渲染,也可能是你的计算逻辑、网络等其他地方造成卡顿。也有可能是内存自动回收造成的卡顿。),
当你经过优化尝试、但卡顿却没有明显减轻的时候,可是试试这个方法:

【个人解决方法】:
由每帧 img.y += iSpeed 执行移动,改为:
let nSpeedScale: number = dt / (1 / 60.0); img.y += iSpeed * nSpeedScale;

在我的项目里,这个方法,比优化了碰撞检测逻辑、使用对象池后的尝试,效果明显的多(但不是说这些优化就不用做了)。

3赞

我的项目在 iOS 上,
Game Logic (ms) 在 0.7 到 1.4 左右波动,
Renderer (ms) 在 5 到 8 左右波动。
波动峰值,主要是拾取物品的时候,会有飘字。

在安卓和PC上,这两项数值都要低一些,体验上也是丝滑般流畅了。

但在 iOS 上的卡顿,仍然不能排除是我的代码写的有问题 :disappointed_relieved:
亦或者,Creator 本身在 iOS 上的性能就比在 Android 上差。

mark

我项目,在ios确实比Android性能差 很多····而且发热严重

就是因为 dt 数值波动太大了所以 dt*speed的值不稳定 会经常跳。导致界面抖动厉害.

我觉得 dt * speed 的计算方式不大合理,
img.y += iSpeed * nSpeedScale; 才是真正的速度恒定。
因为 dt 不稳定,所以我用 nSpeedScale 的方式修正每帧的真实速度,
但表现上始终是 iSpeed 的速度。


自打脸补充:

dt * speed 的计算方式是合理的,理论上其在表现上也能应对帧数抖动。

按你这个时间来算, 这点性能不是根本原因,只要总时间不超过16ms, 就不会出现所谓的帧率抖动。计算方式确实应该是按新的算, 不过旧的在你这也不影响。 只能猜测是整个系统资源占用太高,导致的整体卡顿,可以尝试看下别的游戏是不是也这样。

1、速度*时间
s = speed * dt;


2、事先算好的1 / 60秒对应的路程
iSpeed = speed * (1 / 60);

s = iSpeed * dt / (1 / 60)

=> s = speed * (1 / 60)  * dt / (1 / 60)
=> s = speed * dt

根据我理解的情况,你这么做毫无意义。。。。也许仅仅是错觉而已

我测试了不只一个 iPhone,运行我的项目都有卡顿现象。
刚跑了一下别的同类型小游戏,没有卡顿现象… 但也不知道人家用的是不是 Cocos Creator …

是这样的,
我项目里不是这么用的。
我设定了每秒 60 帧,每帧里,图片移动固定的 iSpeed,就是纯 += 计算。
而且之前也没有用到过 dt 参数(自己写的 Tick 接口,一开始没有把 dt 做参数传过来)。
也就是我的 “速度 * 时间” 是 s = speed * 1

想了想,其实我的做法跟 dt * speed 是一样的…
完了,自己打脸了… :joy:

根本还是主要优化代码减少dt波动 ,除常规优化外,高耗时的操作分帧处理、

即使是空项目的 dt 也有波动,高的可能接近18ms的样子。
但用空项目写的简单的图片滚屏在 iOS 上感受不到卡顿(同屏200+的图片)…
还是得查代码去了… 优化还真是个头疼的问题…

一般更多的是程序逻辑中的耗时卡顿 即使空项目200+图片移动但是逻辑就 pos+=dt*speed 。
优化是很蛋疼,但是优化完很爽阿:relieved:

啊~ 多么痛的领悟~

你的创建和销毁没有必要每一帧都进行判断创建和销毁
单独写一个schedule 间隔时间 改成 2帧或者3帧的时间 进行判断和销毁 试试

判断的时候不要所有的都进行判断,只记录边缘需要判断的才进行判断

update只进行移动处理 把需要更新移动的节点都放在一个root节点下 然后只移动root节点即可

楼上说的有道理,我当时的做法是,用一个纵向的layout放置图片,滑出canvas外的图片也不销毁掉,update中只移动layout节点,没有发现太大的抖动以及内存开销

1赞

mark 感謝大神提供方法

请教各位大神,若是用 node.runAction 代替手动计算座标值,效果会比较好吗?

用谷歌的profile看看吧 帧数浮动跟逻辑还是有很大的关系的

[quote=“182457755, post:15, topic:70151, full:true”]
你的创建和销毁没有必要每一帧都进行判断创建和销毁[/quote]

你这里说的应该是我前面发的 Demo,有坛友指出,那个 Demo 不具有代表性。
而且我实际项目中也没有这么频繁。

这确实是个不错的优化的点子。但是对于现有项目代码,有碰撞检测的逻辑,改起来也不大好改,而且同屏实体不多,手写的矩形碰撞检测足够用,且不会很大耗时开销,也就没去改了。

是的,我终于找到了这个工具,Chrome 默认是不显示这个页签的,在 More tools 里面藏着:

更方便我查找问题了!
在 More tools 下面有个 Setting 里,
typescript 项目推荐不要勾选 ‘Enable Javascript source maps’ 选项,
这样更容易定位到代码行。


以下是我优化卡顿问题的所有提交,
优化仍在继续…


黑人问号脸…