September 22, 2023

一个任务调度算法引起的性能问题

这两天遇到一个任务调度算法引起的性能问题,花了颇多精力排查和解决。问题出在我写的 ltask 这个 lua 多任务库上。ltask 最初是对 skynet 的一些反思中开始的,最初只是想换一种思路实现 skynet :做一个库而不是框架、更少的锁竞争、避免服务因为消息队列堆积而过载……

后来、我们游戏引擎开始尝试基于 ltask 利用手机设备上的多核,渐渐的便完善起来,也发展出和 skynet 不同的部分。它最近两年一直是围绕移动设备客户端程序优化,所以网络部分并非重点,也就不需要像 skynet 那样把网络模块做在框架底层,而是以一个独立服务存在。而网络 IO 、文件 IO 、客户端窗口这些部分又不适合于其它渲染相关的服务混在一起,因为它们需要和操作系统直接打交道,所以我在 ltask 中又分出了独占线程和共享工作线程两种不同的线程,可以把不同的服务绑在不同的线程上。甚至对于 iOS ,还必须让窗口线程运行在主线程上,而不得不在 ltask 里做特殊的支持。

最近发现的这个问题也是游戏客户端特有的,它很能说明用于游戏服务器的 skynet 和用于客户端的 ltask 在实现侧重点上的不同。

阅读全文 "一个任务调度算法引起的性能问题" »

September 19, 2023

桌面游戏的分类

所有在桌面玩的游戏都算作桌面游戏。几乎所有的人都玩过,比如象棋、围棋、扑克。如果不计这些传统的抽象游戏,我玩现代桌面游戏已经有十多年了。过去,是和朋友一起玩,而最近几年,更多的是和家人(小孩)一起玩。和许多不玩现代桌游的人想象的不一样,虽然电子游戏脱胎于桌面游戏,但桌面游戏却并没有被淘汰,反而一直在推陈出新,每年都有许多新的佳作面世。

玩桌游这么些年,我发现桌游其实可以分出几个子类。像我这些各种桌游都玩的玩家很多,但有相当一部分人专注于特别一个子类,对其它类的桌游兴趣不大。有时,隐隐觉得不同子类之间还有一些鄙视链存在。

阅读全文 "桌面游戏的分类" »

September 11, 2023

特效接口的重构

上次提到,经过数据分析发现,我们引擎(游戏)目前特效系统占了很大的 CPU 比例。虽然特效的计算已经放在独立线程,不影响帧率,但 CPU 的开销会导致电池消耗,最终会引起手机热量上升,最终让手机降频。所以,当时想了一些牺牲准确性的方案来做优化:即,不在镜头内的特效不运算。让视觉裁剪同时也裁剪掉特效粒子片的计算。

最近做了这方面的重构工作。其中的难点在于:特效模块是第三方的,并不完全贴合我们的引擎设计,而短期内又没有重新实现或改造的计划。

阅读全文 "特效接口的重构" »

August 14, 2023

疑似 covid-19 二次感染

第一次感染 covid-19 是在去年底,距今已有 8 个月了。

最近似乎又中招过一次,特此记录一下。

上周四( 8 月 10 日)午饭过后,感觉有点困,就靠在办公椅上打了个盹。我平常没有固定午休的习惯,觉得自己是头天没睡好的缘故。14 点多醒了,感觉依旧精神不好。起身去上厕所时发现有些头晕,不过没太在意。

18 点下班时,感觉头晕没有缓和,似乎更严重了。去食堂的路上走路有点飘。没什么胃口,快速吃完,觉得自己的体力不足以步行回家,就搭了个同事的顺风车赶紧回家睡觉。

阅读全文 "疑似 covid-19 二次感染" »

August 07, 2023

手机游戏引擎的优化

我们的手机游戏引擎一直在跟随着游戏项目的进程不断优化。一开始是因为游戏引擎在手机上帧数达不到要求。得益于 ECS 框架,我们把初期用 Lua 快速开发出来的几个核心 system 用 C 重写后,得到了质的飞跃。

其实这些核心代码总量并不算大。例如在 profile 中表现出来的非常消耗 CPU 的一个场景树更新系统,用 C 重写了也才 200 行代码 ,但在优化前 Lua 版本会消耗超过 1ms 的时间,而用 C 重写后,时间已可以忽略不计。

另外,我们采用了类似 skynet 的 ltask 做多线程框架,把业务尽量拆分到多线程中并行处理,这也极大的减少了每帧的耗时。除了主业务逻辑外,UI 、粒子系统、IO 被分为几个并行线程。且渲染底层的 bgfx 也是按多线程渲染设计的。这些并行流程间只通过少量的消息通讯,所以,并行的总工作量并没有比单线程模型更多。ltask 也可以很方便的调节工作线程的个数,用来更好的适配手机的 CPU 。

从xcode 的调试信息看,在游戏场景丰富时,大约会占用 280% 的 cpu 。换句话说,如果我们采用的是单线程架构,在不删减特性的前提下,做到流畅是相当困难的。

阅读全文 "手机游戏引擎的优化" »

July 18, 2023

有序数列的数据结构优化

在我们的 ecs 模块中,有一个重要的内部数据结构是 eid 的数组。它是 Component 结构的一部分,表示每个 Component 属于哪个 Entity 。目前,它是以一个有序的 id 数组实现的。

这个数据结构常见的操作分别是:遍历、随机访问、查找 id 所在的位置。一个有序数组可以很好的完成任务。O(1) 的随机访问时间,O(Log N) 的查找时间。

我们的 Entity ID 是 48bit 的,我觉得保存 48 或 64bit 的 id 数组有点浪费,且空间越大,实际操作效率也会相应降低。实际上,Entity 的个数不会太多,我觉得限制在 2^24 (一千六百万左右)足够了,所以用了一个间接索引,保存 24bit id ,再用它去索引真正的 entity id 。

阅读全文 "有序数列的数据结构优化" »

July 05, 2023

ttf 字体的一点问题

我们的游戏引擎使用的是 stb 的 truetype 库 来处理 ttf 字体的。最近发现在使用公司提供的 阿里巴巴普惠体 时出了一点问题。

引擎渲染出来的汉字比标称的像素高度矮了不少,想渲染 100 像素高的汉字,结果只有 70+ 像素左右。我们之前测试使用的中文字体( Windows 自带默认字体)没有这个问题。

在网上翻了一下,找到这么一个帖子:https://github.com/nothings/stb/issues/689 以及 imgui 也遇到过类似问题

阅读全文 "ttf 字体的一点问题" »

June 21, 2023

手机游戏交互的一点想法

这一篇是延续去年的想法 。最近正在按这些想法改进我们正在制作的一款类异星工厂的手机游戏。

我们的游戏引擎是在 PC 上开发的,但希望专门用于手机。虽然我希望日常游戏开发都在真机上进行,引擎为之也做了很多的努力。但实际并不算顺利。主要还是引擎以及游戏的核心 C 部分还在频繁改动,在真机上调试毕竟不如 PC 上方便。好在最近已经慢慢稳定下来,开发中使用真机的机会越来越多,也就更多的考虑在手机上的交互问题。

我意识到的第一个问题就是:在 PC 上模拟的版本是无法体验手机上的交互感受的,想把手机上的交互做好,就必须时刻在手机上体验。

我们引擎原本的交互界面都是基于鼠标消息,触摸屏消息只是对鼠标消息的模拟。这样是不对的。意识到问题后,我们首先把鼠标消息从引擎中去掉,把触摸屏手势消息改为 first class ,而鼠标消息则反过来用手势消息模拟。

基本手势其实有四个:点击、长按、拖动、缩放。其中在不同场合下,拖动可以被清扫取代,但两者不可共存。

阅读全文 "手机游戏交互的一点想法" »

June 14, 2023

抽王八的新玩法

之前教孩子玩扑克牌,从抽王八入手。孩子们都很喜欢。

这是一个传统游戏,在西方叫 Old Maid

规则很简单,就是把一副 54 张的扑克牌中抽掉一张王和一张 8 (或其它任意牌)。把牌平均发给参加的玩家。每个玩家将得到的牌中成对的牌都扔掉,保留在手上的全部是单牌。然后,每个人每个回合抽下家一张牌,如果能和手上已有的牌配对,便可以把成对的牌扔掉,否则必须把抽到的卡保留在手中。先打完手牌的玩家胜利,而到游戏最后,最后一个玩家手上肯定保留了一张王和一张八,而其他玩家都出完手牌。

这种玩法非常简单欢乐,小孩子一学便会。但我觉得玩起来毫无技巧可言,所以我最近把规则改进了一下,变成了一个非常依赖记忆力的游戏。

阅读全文 "抽王八的新玩法" »

June 02, 2023

近期 ECS 的一些优化

最近在优化我们的 3d engine 。引擎的渲染对象管理层是基于 ECS 框架,且整个引擎基于 Lua 设计和构建。也就是说,渲染部分的数据都可以通过 Lua 读写。但是,对于核心渲染循环,Lua 的性能有限,当需要渲染的对象很多时,之前用 Lua 编写的循环的性能问题就显露出来。

为此,我们很早就设计了 luaecs。把数据放在 C 结构中,并给出 Lua 访问的接口。这样就方便了初期使用 Lua 快速开发,后期针对核心循环用 C 重构优化。今年年初时,我们把渲染核心系统用 C 重构了一遍,基本解决了性能问题。

阅读全文 "近期 ECS 的一些优化" »

May 29, 2023

Apple watch 折腾记

云豆想要一块电话手表。我了解到现在的小孩大多用小天才儿童手表,但考虑到云豆其实没有什么社交需求,我自己也有一块 apple watch ,所以想试试给他买一块。最初的想法是,儿童手表过两年估计娃就不愿意带了,而 apple watch (系列)可以用到成年。而似乎 apple 似乎也愿意做儿童市场,现在 apple watch 有家人使用的模式,不妨试试。

周六,网上订购的 apple watch se 到了。我给他创建了一个苹果的儿童账号,很顺利的就设置好了手表。但简单适用了之后就被劝退。apple watch 的家人模式功能上大打折扣,手表其实还是挂在我账号下的,而表上多绑了一个儿童账号。这导致除了苹果官方默认 app 之外,几乎所有的 app 都不能安装。包括微信支付宝这些。除了打电话,能用的通讯就只剩下 iMessage ,对小孩几乎没什么用。我想在手表上装个交通卡也未能成功:因为年龄不够(苹果要求 14 周岁),不能在钱包里添加卡片。苹果官网查了一下,儿童账号的支付功能只在美国才能开。

阅读全文 "Apple watch 折腾记" »

May 15, 2023

带娃玩桌游的第二篇

今天有同学在老帖子 上留言,看到下面杨博去年问这方面有什么进展,想想应该补上这么一篇。

最近几年,因为疫情的缘故,在家的时间比较长。孩子也长大了不少,能开的桌游多了许多。我现在几乎很少在外面和朋友玩桌游了,而在家几乎每周都会开三到四次。

云豆马上九岁了,可可也已经六岁半。兄妹俩的喜好已经明显有区别,我们能一起玩的桌游不多,一般我都是分开带哥哥玩,或单独带妹妹玩。不过有一款游戏大家一起玩的很多,那就是 Splendor (宝石商人)。

这款游戏发行商标注的是 10 岁+ ,在 bgg 上用户投票以 8 岁+ 居多,我感觉也是。7,8 岁的年龄完全可以充分理解游戏规则,制定整局规划。可可不到 6 岁多点也能玩,但是年纪比较小,仅能理解规则,无法深度思考怎样赢得游戏。好在她的胜负心很弱,每次输掉都能自我开解:玩个游戏嘛,输赢无所谓的。

阅读全文 "带娃玩桌游的第二篇" »

May 01, 2023

记一次艰难的 debug 历程

五一前,我遇到了一个非常难缠的 bug ,前后花了两天时间才把它解决。其刁钻程度,可以列入我职业生涯的前三,非常值得记录一下。

问题发现在节前两天,很多同事都请了假,我也打算好好休息一下,陪孩子玩几天。就在我例行更新游戏项目的仓库后,突然发现程序崩溃了。一开始,我并不以为意。因为我们的游戏是用 Lua 为主开发的,并不需要在更新后重新编译。我大约一周才会构建一次项目。或许这只是因为我太久没有 build 了,所以我随手构建了一下。但问题依然存在,只不过发生的概率偏低,大约启动三次有一次会出问题。这不寻常,因为我已经很久没见过 Segmentation fault 了。

阅读全文 "记一次艰难的 debug 历程" »

Misc

Categories

Archives

Recent Comments