November 27, 2020

粒子管理器的 C++ 封装

这篇接着上一篇 粒子系统的设计

TL;DR 在花了一整个晚上用 C++ 完成了这一块的功能后,我陷入了自我怀疑中。到底花这么多精力做这么一小块功能有意义么?强调类型安全无非是为了减少与之关联的代码的缺陷,提高质量;但代码不那么浅显易懂却降低了质量。

我们用 C 实现了一个基于 ECS 结构的粒子系统的管理器,代码 psystem_manager.h 在这里

先来回顾一下设计:在这个粒子系统中,我期望把粒子对象的不同属性分开管理。

即:传统的面向对象的数据结构中,一个对象 particle 可以有很多属性 a,b,c 。通常是用一个结构体(或类)静态定义出来的,这些属性也可以看作是 a b c 组件,它们构成了粒子对象。而在 ECS 结构中,我们在每个时间点,并非去处理一个对象的多个属性,而是处理同一个属性的多个对象。所以,我们最好按属性分类将多个对象的同一属性聚合起来,而不是按对象,把同一对象的不同属性聚合在一起。

这是因为,在处理单个属性时,往往并不关心别的属性。比如,我们在递减生命期,处理生命期结束的对象时,关心的仅仅是生命期这个属性;在处理粒子受到的重力或其它力的影响时,我们只关心当前的加速度和速度;在计算粒子的空间位置时,只关心上一次的位置和瞬间速度;而在渲染时候,无论是生命期、加速度、速度,这些均不关心。

当数据按属性聚合,代码在批量处理数据时,连续内存对 cache 友好,即使属性只有一个字节,也不会因为对齐问题浪费内存。同一属性的数据尺寸完全相同,处理起来更简单。而且粒子对象相互不受影响,我们只是把同一个操作作用在很多组数据上,次序不敏感。非常适合并行处理。

更重要的是,不同类型的粒子需要自由的根据需要组合属性和行为。有的粒子有物理信息参与刚体碰撞运算,有的则只需要显示不需要这个信息;有的粒子有颜色信息,有的不需要有;有的粒子是一个面片,有的却是一个模型,拥有不同的材质。这导致粒子对象包含的信息量是不同的。及时拥有同一属性,作用在上面的行为也可能不同:例如同样是物理形状信息,可能用于刚体碰撞,改变运动轨迹,也可能只是为了触发一下碰撞事件。

在传统的面向对象的方式中,常用多态(C++ 的虚函数)来实现,或者有大量的 if else switch case 。

如果能按组件和行为聚合,那么就能减少大量的分支。每个粒子的功能组合(打开某个特性关闭某个特性)也方便在运行时决定,而不用生成大量的静态类。

阅读全文 "粒子管理器的 C++ 封装" »

November 19, 2020

粒子系统的设计

这几天在重构引擎中的粒子系统。之前用 lua 做了个原型,这次用 C/C++ 重新实现一次。目前还是基于 CPU 的粒子系统,今后有必要再实现基于 GPU 的版本。

去年写过一篇 blog 也是谈粒子系统的 。 思路大致类似,但这次在数据结构的细节上做了一些专门的设计,有觉得还有点意思,值得写写。

首先,粒子对象本身就是一个集合了多种数据的数据块。我限制了同时最多 64K 个粒子片,这些粒子对象可以放在一块连续内存中,并且可以用 16bit 的 id 进行索引。

阅读全文 "粒子系统的设计" »

November 08, 2020

Lua binding 的一些方法

这几天在给 RmlUi 这个库写 Lua binding 。

这个库原本有一个官方的 lua binding ,但是新特性 Data Model 却没有实现。作者坦承自己对 Lua 不是特别熟悉,这个新特性也在开发中,暂时没想好该怎么做,所以只完成了 C++ 接口,Lua 接口留待这方面跟懂的人来做。

我觉得这个新特性有点意思,打算帮助这个项目实现 Lua 接口。在实现的过程中,发现原版的 Lua binding 做的过于复杂,且那些复杂度完全没有必要。所以打算自己全部重新实现一套。

阅读全文 "Lua binding 的一些方法" »

October 20, 2020

skynet 1.4.0

又是一年过去了,skynet 目前保持着一年一个发布版的开发进度。skynet 1.4.0 发布版将于近期冻结。

这次的主要更新是将 Lua 更新到了 5.4.2 (尚未发布,但 github 仓库中的版本号已经到了 5.4.2 )。可能会让 skynet 的许多项目享受到分代 gc 的好处。如果使用大量 agent 服务的模式,将会降低整体的内存峰值开销(GC 更加及时)。lua 5.4 中 table 的内存开销也比之前的版本要小,运行性能也有所提升。

升级到 lua 5.4 基本不需要修改过往的 Lua 代码。C 库需要重新编译,但基本不需要修改。但如果可以改用新版的 lua_newuserdatanv 取代 lua_newuserdata 会更好。

skynet 依然提供了针对多 vm 共享 proto 的补丁。和以前一样,这是一个可选项,可以自行编译官方版本的 lua 。

阅读全文 "skynet 1.4.0" »

October 18, 2020

cache server 问题总结

这周,我们的 cache server 服务面临了很多的挑战。项目资源超过了 30G ,有几十个用户在同时使用。每天都有版本切换工作(导致重新上传下载 30G 的数据)。在这个过程中,我对 cache server 程序修修补补,终于没有太大的问题了。

总结一下,我认为 cache server 的协议设计,以及 Unity 客户端实现,均存在很大的问题。这些问题是无法通过改进服务器的实现彻底解决的,只能做一些缓解工作。真正的完善必须等 Unity 的客户端意识到这些问题并作出改进。

cache server 的协议设计非常简陋。就是顺序的提交请求,然后每个请求会有序的得到一个回应。这些请求要么是获取 GET 文件,要么是上传 PUT 文件。其中 PUT 文件在协议上不必回应。

由于 PUT 文件没有回应,所以客户端无法直接确定文件是否全部上传完毕;如果必须确认,只能在 PUT 文件结束后,再提交一个 GET 请求。如果收到了后续 GET 的回应,可以理解为前一个 PUT 已经结束。实际上,Unity 客户端没想去确认 PUT 是否结束,从 log 分析,它只是简单的在最后一个 PUT 结束后等待了一段时间再断开连接。

PUT 实际上是个小问题,真正的问题是:这种依赖严格次序的协议,在面对两边数据量不对等、网络速度不对等的近况时,很难有一个健壮的实现。

阅读全文 "cache server 问题总结" »

September 21, 2020

skynet 版的 cache server 引出的一点改进

我们自己做的 cache server 已经工作了很长时间了。上次出问题是在 2 月在家工作期间

这个月又出了一起事故,依旧是 OOM 导致的崩溃。一开始,我百思不得其解,感觉上次已经处理完了所有极限情况,按道理,这是个重 IO 而轻内存的业务,不太可能出现 OOM 的。

通过增加一些 log 以及事后的分析,我才理解了问题。并对应做了修改。

阅读全文 "skynet 版的 cache server 引出的一点改进" »

September 03, 2020

为 skynet 增加并行多请求的功能

skynet 在设计时,就拒绝使用 callback 的形式来实现请求回应模式。我认为,callback 会导致业务中回应的流程和请求的流程割裂到两个执行序上,这不利于实现复杂的业务逻辑。尤其是对异常的支持不好。

所以,在 skynet 中发起请求时,当前执行序是阻塞的,一直等到远端回应,再继续在同一个执行序上延续。

如果依次发起请求,会有不该有的高延迟。因为在同一个执行序上,你必须等待前一个请求回应后,才可以提起下一个请求。而原本这个过程完全可以同时进行。

但是,如果我们想同时发起多个不相关的请求就会比较麻烦。为每个请求安排一个执行序的话,最后汇总所有请求回到一个执行序上又是一个问题。目前,只能用 fork/wait/wakeup 去实现,非常繁琐。

这类需求一直都存在。我一直想找到一个合适的方法来实现这样一类功能:同时对外发起 n 个请求,依回应的次序来处理这些请求,直到所有的请求都回应后,再继续向后延续业务。实现这样的功能在目前的 skynet 框架下并不复杂,难点在于提供怎样的 api 形式给用户使用。

阅读全文 "为 skynet 增加并行多请求的功能" »

August 19, 2020

银河竞逐的设计

银河竞逐 RFTG 是我最喜欢的桌游之一。我认为直到今天,它仍旧是最棒的引擎建造类卡牌游戏。最近,我看了银河竞逐的作者 Tom Lehmann 在 GDC2018 上的演讲 非常有收获,所以写这篇 Blog 分享一下。

策略竞争类的游戏一定要设计多种结束条件。RFTG 的基础版设计了建造出 12+ 张卡结束和分完 12n 个 VP 结束。基础策略就可区分为快速打出一堆小分卡,还是构造一个 VP 引擎。我最近玩得比较多的五扩(Xeno Invasion)还增加了击败(或被击溃)Xeno 结束。

这样可以使得创造出 strategic tension 。

阅读全文 "银河竞逐的设计" »

August 04, 2020

Evidence-based software engineering

《The New C Standard》 是我很喜欢的一本书。因为这本书,我有幸结识了作者 Derek M Jones 。

在 2018 年的时候,他就写 email 给我介绍了他正在写的一本关于软件工程的书。

这是一本非常特别的书。里面有大量的、从公开渠道获得的关于软件工程方面的数据。作者对这些数据做了统计和分析。我之前从未看过如此全篇基于数据去讨论软件工程领域问题的著作(通常在社会学领域更多一些)。

数据摆在那里,或许不同的人,不同的方法会得到不同的解读。这本书不在于给出结论,而是展示了分析过程。让你来从中发现数据透露出的信息。

当时我就很喜欢这本书,陆陆续续读了一些。

最近,这本书《Evidence-based software engineering —— based on the publicly available data》终于快完成了。我很高兴能分享给大家,有兴趣的同学可以在这里下载电子版

如果有同学有兴趣公开自己的一些有关软件工程方面的数据,还可以看看这里

July 21, 2020

裁剪和空间管理

今天想谈谈游戏引擎中 Culling 模块。

当场景中的可渲染对象很多,而当前会被渲染的对象相较甚少的时候,我们通常会启用一个 culling 的过程。Culling 会想办法剔除一些当前不必渲染的对象,避免这些对象提交到 GPU ,让 GPU 承担剔除的过程。这样可以减少 CPU 到 GPU 的带宽。

最基本的 Culling 是用相机的视锥体和对象做一个相交测试,如果对象和视锥体不相交,则可判定它不必渲染;复杂的 Culling 还包括遮挡测试,如果一个对象完全被墙体挡住,那么也不必渲染。这篇只谈前者。

很容易得知,Culling 算法的复杂度上限为 O(n) 。即,我们把场景中的每个对象逐一和视锥体做一次相交判断即可。这里的 n 为场景中元素的个数。

当 n 特别大的时候,通过巧妙地设计数据结构,我们则有可能把复杂度降低。但如何做到呢?

阅读全文 "裁剪和空间管理" »

July 16, 2020

动态字模的管理

在上一篇 blog 中,我谈到了 UI 模块。而 UI 模块中绕不开的一个问题就是怎么实现文字渲染。

和西方文字不同,汉字的数量多达数万。想把所有文字的字模一次性烘培到贴图上未尝不可,但略显浪费。如果游戏只是用有限几种字体倒也不失一种简单明了的方法。但如果使用字体丰富,而多数字体只使用几个汉字,那么就不太妥当了。

我在设计 ejoy2d 的时候实现过一版动态字模的管理。但我觉得略显简陋。最近重新做了一版。

阅读全文 "动态字模的管理" »

July 09, 2020

游戏 UI 模块的选择

在游戏(包括引擎)开发的过程中,谈及 UI 模块,通常所指有二:

  1. 开发工具所用到的 UI 。
  2. 游戏本身所用到的 UI 。

这两者很多时候都是共用的一个模块,比如之前的 Unity 就直接把引擎开发用的 UI 模块扔给开发者开发游戏使用。但很快,开发者就发现,适合工具开发的 UI 模块,在做游戏时就不那么顺手了。所以就有了第三方 UI 插件的流行,以至于最后又倒逼 Unity 官方重新制作游戏 UI 模块。

开发工具面临的需求和游戏场景面临的需求很不一样:

开发工具需要的时候更好的将内部数据以可视化方式呈现出来,供用户浏览和修改,以适应数据驱动的开发。UI 的呈现需要的一致性,风格统一有利于减少学习成本,同时需要清晰的表达复杂的数据结构。有时还需要将内部数据的变化过程同步的动态呈现,给开发者更直观的感受。

游戏 UI 是游戏过程的情感体验的一部分,外观和交互需要根据游戏设计专门化。它往往并不需要表达游戏内部复杂的数据结构,而是将那些数据以额外面对玩家的形式展现出来。玩家通过界面下达的指令也并非直接对数据的修改,而是以指令流的形式传递过去。另外,HUD 也是很大的一个部分,和 UI 对话框在设计上也有很大的不同。

他们两者之间在技术上的共性其实很小,针对这些共性的技术实现可能也只有几百到上千行代码的规模,远少于差异部分需要的代码量。我比较倾向于把这两个东西分开实现。

阅读全文 "游戏 UI 模块的选择" »

June 16, 2020

skynet 并发模型的一点改进思路

skynet 的内核是一个多线程的消息分发器。每个服务有一个消息队列,任何服务都可以向其它任意服务的消息队列投递消息,而每个服务只可以读自己的消息队列,并处理其中的消息。

目前的工作原理是,在任意消息队列不为空的那一刻,将该消息队列关联的服务对象放在一个全局队列中。框架启动固定数量的工作线程,每个工作线程分头从全局队列中获取一个服务对象,并从关联的消息队列中获取若干条消息,顺序调用服务设置的回调函数。如果处理完后消息队列仍不为空,则将服务对象重新放回全局队列。

这样,就完成了尽量多(远超过工作线程数量)的并发服务的调度问题。

我这些年一直在考虑这个模型可否有改进之处。能不能设计得更简单,却还能在简化设计的基础上进一步提高并发性。同时,还可以更好的处理消息队列过载问题。

阅读全文 "skynet 并发模型的一点改进思路" »

Misc

Categories

Archives

Recent Comments