14

游戏性能优化杂谈(六)

 3 years ago
source link: https://zhuanlan.zhihu.com/p/268625172
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

游戏逻辑的执行,也是CPU端性能瓶颈的常见原因之一。

当代游戏引擎的一大进步,是将游戏逻辑的制作从程序员手中解放出来。WYSIWYG的可视化编辑,基于脚本语言甚至是节点连线的二次开发,都大大降低了编写游戏逻辑的技术门槛。但是正如老话所说,“甘蔗不能两头甜”,这一切是以CPU端的执行性能牺牲作为代价的。

在我经历过的各种软件行业和软件项目当中,游戏可以说是最为在面向对象这个问题上纠结的一个了。一方面,游戏本身内容的组织上具有非常强的对象特性:无非是一群actor在一个舞台上按照剧本表演,并且根据一些预设逻辑与玩家(的代理)互动。所以从这个角度来说,以面向对象的手法去开发游戏看起来是最为符合人的直觉的。

但是另外一方面,面向对象在理论上假设各个对象是自治的,并行的。但是实际的执行平台的资源却是高度受限的。这就导致CPU必须采用一种类似时分复用的方式,将执行时间分配给游戏当中的众多对象来推演其状态变化。而且,这种推演必须被送给所有处于活动状态当中的对象:因为在面向对象的思路当中,对象的状态是由其自身管理的,外部只能通过交互去影响,但不能去直接决定。

这就是说,引擎在每个CPU周期当中,必须去遍历所有处于活动状态的对象,并且调用其一系列方法,去驱动其状态的改变,哪怕该对象其实与玩家并不会有任何交互。

几年前有几款上PS平台的独立游戏,问题就发生在这里。当画面当中的敌人一多,画面就开始疯狂掉帧。后来分析发现,因为敌人其实就是那么几种类型,根据面向对象的概念,游戏开发者制作了这几种类型敌人的stereotype(原型),然后不断的instance(实例化)来生成敌人。因为这些敌人都是对应的同一个原型,它们各自都会在每一帧完整执行所有的游戏逻辑脚本,包括攻击判定等。但是,实际上真正能够摸着玩家的就那么几个,其它大部分因为攻击距离等问题是没有可能摸到玩家的但是它们的相关脚本依然是在不断被执行,白白浪费CPU资源。

对于这种情况,其实以前的面向过程的设计方式,往往能够获得更加优秀的性能。与其盲目推演各个对象的状态机来判定攻击行为,不如根据攻击时间和范围来直接更新各个actor的状态。

再举一个例子。数年前有一款射击游戏,制作者也是将子弹stereotype化,给它挂了一个脚本,负责其移动和命中判定。但是后来发现子弹一多就开始疯狂掉帧。其实,只要不是导弹或者制导炸弹,子弹一经射出轨迹就是固定的。那么,子弹能否命中其实就是一个简单的求交问题,大部分情况并不需要每帧都去测试一下。至于子弹的飞行,其实只要轨迹确定,剩下的基本就是沿着轨迹的动画播放,根本不需要状态的推演。

游戏在很多时候都是障眼法,用1帧计算结果,用好几帧进行表演。如果不管三七二十一什么都用OO那套一帧一帧的去推演状态机,那性能自然是不会太好的。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK