下载 App

关于游戏《因果》为什么需要在屏幕刷新率为60hz的环境下运行

修改于2025/11/0632 浏览综合
在这里感谢《窗口旅行 Out Of Bounds》的作者发现了最大的问题,请大家多多支持《窗口旅行 Out Of Bounds》
如标题所示,这一篇帖子用于说明最大的恶性bug出现的原因
在完整说明之前需要知道开发《因果》时使用的技术和前置知识储备
在游戏引擎的普及下,大部分开发者会遗漏一个很致命且隐性的问题:游戏运行时的帧数
有一小部分pvp游戏,会出现“屏幕刷新率高,游戏运行的帧数越高”的问题,例如《Bodycam》
这看起来是一个好结果,但它实际达成的效果却是由设备优劣带来的不对等体验,尤其是基础体验
拿最基础的移动举例子,如果奉行“屏幕刷新率高,游戏运行的帧数越高”就会出现以下结果:
“屏幕刷新率越高,相较于其他屏幕刷新率比你低的设备,你移动的越快”
为什么会出现这种情况?
在游戏开发时都会选择一个基础的动画更新函数来制作和判断角色当前的状态和信息
本质上来讲,动画更新函数就是一个定时器,在启动的时候就规定每隔一段时间就执行一次,直到这个定时器被移除(停止)
例如移动,先写一个函数,告诉编译环境“我需要将玩家移动到离当前位置距离为x,方向为v的位置”
然后将其放进动画函数里,动画函数就会按照规定的时间跨度一直持续执行“我需要……”这个函数
很多时候,由于开发者的疏漏或考虑不周,如果移动速度为x,他们会直接设定为“每一帧移动x这么远”
这是非常严重的错误
如果没有额外的锁帧技术,游戏每一帧将会以一个绝对的距离更新位置,但游戏运行的帧速不一定是绝对的
例如在一些高端设备游戏能够跑到90帧,意味着每一秒会执行移动90次,如果移动速度为10,那么在这个高端设备上一秒的移动距离为90*10=900
但在一些中低端设备只能跑60帧,这时一秒只会执行移动60次,在这个低端设备一秒的移动距离为60*10=600,一秒移动的距离直接少了接近一半
连最基础的移动都会受到如此大的影响,更不用说其他需要额外判定的功能和需要实际播放的动画
这下问题明了了,但如何解决?
我的答案是规定一个绝对的时间跨度(每隔16毫秒)更新一次动画,也就是一秒更新60次(1000/60≈16.6,这里取整为16毫秒)
请注意,这并不是说等到16毫秒后再执行一次动画更新函数,动画的执行和动画更新函数的执行是分开的
动画更新函数依旧按照原有的最高帧率执行,但在其中获取此次调用动画更新函数的时间戳,在判断到下一个时间戳之间的差大于等于16毫秒后就执行一次动画函数
具体例子为:
我有一个函数的名称为fun移动(),动画更新函数的名称为fun更新()
fun更新()执行的时候会获取一次时间戳,假设当前的时间戳为0
fun更新()第二次执行的时候又获取一次时间戳,假设当前的时间戳为8毫秒(模拟120帧的情况),此时时间差为8-0=8毫秒,不够16毫秒,所以继续执行fun更新()
fun更新()第三次执行的时候又获取一次时间戳,假设当前的时间戳为16毫秒,满足16-0=16毫秒的条件,此时执行一次fun移动(),恢复时间戳记录时间为0,继续进行从第一步的判断
这套方法的好处是对于一些帧动画有很强的适配性(例如2d格斗游戏中的动作序列帧),不会出现因为帧数高而导致快速鬼畜播放的效果
知道了帧数如何影响游戏体验后,再来谈谈《因果》中出现的“高于60hz就会卡死”的bug
我目前的所有游戏作品均由H5技术(html+css+javascript)开发,目的是为了进行多平台打包和分发,其中pc端使用nw.js来打包成exe文件,移动端使用cordova来打包成安装包
在js(javascript)中一般使用requestAnimationFrame()来更新动画,这个函数可以跑满设定的最高屏幕刷新率的效果来执行,且每次调用的时候都会返回一个名为currentTime的时间戳
方案和上文中提到的方案一样,但问题是我错误地将“恢复时间戳记录时间”这一行写到了函数末尾而不是“判断时间差大于16毫秒”里
TapTap
这是冲刺代码,本来lastTime=null这一行应该写成lastTime=currenTime的
下面是较为完整的代码
TapTap
谨记不要熬夜写代码
我当时的思路应该是通过给lastTime赋值为null,再进行判断就会达到更新lastTime的目的
结果把lastTime=currentTime放到了函数的最后面
这就导致每执行一次动画更新函数都会恢复一次时间戳记录时间,在高刷屏上根本不会达成判断条件(即frametimeset>=16),预期中的下一帧根本不会到来,导致画面卡死(但仍然在运行)
解决方法很简单,将lastTime=null改成lastTime=currenTime,或将本存在于函数末尾的lastTime=currenTime移动到最前面
问题是所有的动画控制方案都是这个模板,想全改是一项十分难绷的工程
另外还有一些有动态刷新率的设备,保不准真的会以一个很低的刷新率来运行
还是谨记不要熬夜写代码吧
还好在正式上线之前《窗口旅行 Out Of Bounds》的作者反映了游戏按下shift键就会卡死的现象,经过排查后确定是屏幕刷新率的问题,紧急处理后在开头新增了需要将刷新率调到60hz才能游玩的提示
在这里再次感谢《窗口旅行 Out Of Bounds》的作者,也希望大家多多支持《窗口旅行 Out Of Bounds》!
猜你想搜
因果 60hz刷新率原因
攻略截图
攻略
以防大家卡关,现在对游戏机制做一些说明 首先需要将屏幕刷新率调整到60hz才能正常游玩是硬性bug,属于代码层面的问题,不是节目效果,是真的bug 因为熬夜写代码的原因在请求动画帧的时候把一个关键语句写错了顺序,导致屏幕刷新率高于60hz的情况下永远无法请求下一帧,整个游戏就会卡死(但误打误撞发现了时停和时缓的写法,也算因祸得福?) 角色有san值,在枪里有子弹的情况下射击不会扣除san值,枪里没
官方
5 赞
1 回复
有关《因果》的技术详解截图
有关《因果》的技术详解
#聚光灯游戏开发心得接力 在《因果》中我使用了一系列不常用的思路来制作游戏,希望我现在的思路在以后还是有帮助 首先想分享的是碰撞检测 一般来说,进行碰撞检测常用的方案是碰撞体,即检测玩家是否与障碍物进行碰撞 在我上一个游戏《T.B.I》中使用的就是这种技术 另外说明一下,我使用的是h5技术(html+css+javascript)来制作游戏,目的是为了实现跨平台打包和分发,在pc端使用nw.js
7 赞
1 回复
《因果》内容更新
截至到这篇帖子发布为止,新版本已提交审核。 这次更新将带来新挑战,新敌人,新背景音乐以及新剧情 所以屏幕刷新率的问题修了吗? 没有修,而是用更“强势”的方式绕过了这个问题 为什么不修? 史山代码已经堆得看不到头了,就算是我也无能为力 那这次更新有什么值得玩的吗? 这次更新略微调整了游戏平衡和游戏细节,多次死亡之后会重置整个游戏,避免后期因为特性无法继续游戏的问题 那之后还会继续更新吗? 应该不会了
官方
3 赞
安卓端没有无尽模式
由于上传的时候选错版本,安卓端完成demo之后就没内容了 现在也不能再进行审核了 但万幸的是pc端是有无尽模式的,在出现过的地图内轮换并夺得高分,音乐也变成了随机播放 就这样吧
官方
4 赞
00:07
目前T.B.I重置版的进度截图
目前T.B.I重置版的进度
虽然很艰难,但大体框架还是搭好了 整个几乎算是重构,代码完全没有能共用或继承的部分 画面表现承接游戏《因果》的俯视角+3d的风格,虽然看起来没什么变化,但需要的性能大大降低了 在《因果》中移动每一个敌人使用的方案会导致整个页面的元素重排和重绘,虽然在pc端的表现较好,但在其余设备内的表现可以用惨不忍睹来形容,并且在《因果》的无尽模式中随着游戏时间的增加会出现各种各样的性能负担,而这就是这次引擎更新
4 赞
1 回复
有关《因果》的设计思路以及一些(目前)没有做进去的内容截图
有关《因果》的设计思路以及一些(目前)没有做进去的内容
#聚光灯游戏开发心得接力 好,是时候谈谈我是如何设计这个demo的了 通关的朋友可能在demo结尾听crisk讲了一点有关这个游戏的设计初衷,但碍于篇幅原因没能将细节完整展示,并且由于上线前对其中的机制进行了细微的调整,导致后续上传的版本与原先的设计有出入,所以她分享的设计和最终版本不太符合 一些通关的朋友也对游戏的机制有困惑,所以在这里将整个设计思路进行详细讲解 本篇更像长篇杂谈,属于梦到哪句
精华
3 赞
00:17
开发进度(10.16)截图
开发进度(10.16)
看起来只是加了一张背景图片作为场景对吧? 事实是写了完整的场景加载函数,场景脚本函数,并将其接入一个在外部维护的元素属性map里 因为直接读取元素的各类属性消耗的性能会多一些,为了让我的民用c4在调试时不进行一些反应明显的熵增活动只能麻烦一点 属实是燃尽了 好无力的攻击动画,但已经尽力了 #聚光灯gamejam开发者日志 #TapTap聚光灯独立游戏
5 赞
2026主题思考截图
2026主题思考
这个是百度给出的答案,现在(大部分,也许,说不定)用来指代ai的技术发展,主办方的立意也许正是这个,而不是“突然出现的大量事物(尤其特指水)” 既然涌现是“依托简单的规则发展成复杂的结果”,那么最直观的就是半物理/物理格斗游戏里的连招了 拳,脚,身体姿态,通过组合这些要素形成连贯/强力的连招压制对手 或者跑酷游戏,起跳时改变身体姿态穿过各种障碍或空隙 功能实现的话格斗游戏的可拓展性和可玩性是最高的
4 赞
00:13
开发进度(10.11,凌晨)截图
开发进度(10.11,凌晨)
强度很高的闪身 闪身需要消耗行动点才能发动,而且设定的行动点上限很少,只有三行动点,所以不能无限发动 由于电脑转轴坏了,接下来可能又得耽搁几天,所以到这篇帖子发布时算是硬顶着困意肝出来的 诸事不顺啊诸事不顺 要不要加点后摇和前摇呢? #聚光灯gamejam开发者日志 #TapTap聚光灯独立游戏
5 赞
00:21
开发进度(10.15)截图
开发进度(10.15)
现在添加了行动点限制以及原地恢复行动点的机制 所有动作都可以在有行动点剩余的情况下主动消耗一个行动点来取消并立即回到待机状态,旨在取消后摇或进行佯攻 攻击,闪避,格挡这三个状态需要消耗行动点来主动发动,通过限制行动点上限来迫使玩家依照当前情况制定接下来的策略 可以主动原地恢复一行动点,但整个过程就是原地罚站且不能做任何预输入 至于为什么是arrAp[i-1]而不是当前序号的元素的边缘亮起,现在还没
5 赞