« August 2016 | Main | October 2016 »

September 19, 2016

ephemeron table 对 property tables 的意义

今天在公司群里,Net bug 同学提出了一个问题,围绕这个问题大家展开了一系列讨论。讨论中谈及了 lua 中的一个常见的模式:property table ,我觉得挺有意思,记录一下。

最初的问题是:当一个对象的某些属性并不常用,希望做惰性初始化的话,应该怎么实现。

我认为,property table 是一个很符合这个案例的常见模式。

比如,对象 f 有三个可能的成员 a b c ,我们可以不把 f.a f.b f.c 记录在 f 这个 table 里,而是额外有三张大表,a b c 。利用 metatable ,可以在访问 f.a 的时候,实际访问的是 a[f] 。也就是说,所有同类对象的 a 属性,都是从 a 这张表里访问的。

a 这张表的 key 就是对象,value 是对象对应的 a 属性值。

这样做有什么好处?

当对象的运行时用到的属性数量不一时,对象本身占用的空间是固定的。这里的对象变成了带 metatable 的空表,真正的属性值是统一放在有限张大表中的。

大表可以预先分配好内存,而空表占的内存很小且固定,对内存分配器特别友好(容易实现 freelist )。

操作对象本身,不会因为增加属性而造成 rehash 。如果你并不能在对象初始化的时候就决定空间(会改写多少属性),那么好处就会很明显。

另一个明显的好处是,如果你的对象很多,但是有少数对象会设置某种标记或回调函数,然后需要遍历这组特殊对象时,实现方便、性能更高。

我们有一个实际的优化案例:

心动庄园 的项目中,客户端有大量的对象,只有部分对象带有动画。而带有动画的对象是需要每帧多处理一些事情的。

处理的逻辑之前大致是这样的:

for obj in pairs(objects) do
  if obj.update then
    obj:update()
  end
end

在最近一次性能剖析时发现,objects 集合特别大,而需要调用 update 的对象比较少,造成了很大的浪费。所以在优化方案中,我们在设置 update 的时候把对象对象放在另一个集合中,每帧只需要遍历这个较小的集合就够了。

但是,如果一开始我们就用上面提到的 property table 模式,就天然解决了这个问题。因为所有的 update 方法都直接放在了一个集合中了,没有设置这个方法的对象天然就不存在于这个集合。


这里为什么要提到 lua 5.2 后引入的 ephemeron table 这个特性呢?

因为,我们需要把这个 property table 设置为弱 key ,也就是 lua 5.2 文档中所描述的 ephemeron table 。

在 lua 5.1 中,由于没有 ephemeron table 的支持,有可能因为循环引用问题而导致无法回收某些 property 。

例如:如果一个对象有一个属性 ref ,当你设置

a.ref = b
b.ref = a

时,会造成循环引用。 ref 这张表里,ref[a] 和 ref[b] 相互引用,导致即使在表外 a b 对象都已不存在了,还是回收不掉。

ephemeron table 解决了循环引用的问题,参考 Eliminating Cycles in Weak Tables

September 14, 2016

Shop Heroes 的公会系统

上一篇谈到了 Shop Heroes 的经济系统,这一篇想谈谈它的公会系统。

和很多其它网络游戏不同,Shop Heroes 的公会系统并不是一个可以被剥离的系统,它和整个游戏,包括其经济系统是密不可分的。我觉得这个系统是为了完成其游戏的根本设计目的:引导玩家差异化发展从而制造出市场需求,而设计出来的东西。

在游戏中,不存在未加入公会的玩家。玩家在新手教学阶段就会被强制引导到一个叫做外城的环境,也就是游戏中的公会。你必须选择加入一个已有公会,或是自己创建一个单人公会,否则游戏无法进行下去。

在游戏的前几十小时,一个人玩其实也没有任何障碍。你可以把公会建筑看成是个人资产的一部分,该升级升级。但在上一篇提到过,游戏中用来升级的金币最终会成为紧缺资源,总有一天你的收入会承担不起。当然,作为一个固执的 RMB 战士,你还是可以一个人玩下去的,城市升级可以用钻石替代。而且很贴心的设计成非线性对应关系。正如上一篇提到的,金币随等级不同(生产能力成指数上升),其价值也不同。所以如果你想投资 20K 金币,可以用 80 钻替代;而一次投资 500K 的话,就只需要 300 钻而不是 2000 钻了。

相比一个人用钻石经营一座城市,更经济的方法是加入一个公会,大家共同建设一座城市;对于个人来说只有好处,没有任何坏处,何乐而不为呢。

在 Shop Heroes 里,投资到公会城市里的每一笔金币,都始终是记在个人头上的。城市的整体效果永远是公会里每个人的投资之和。如果你离开换到新的公会,会带走所有历史的个人投资加到新公会里。老公会会减去带走的投资。换公会对个人没有任何损失,所以你不必斤斤计较到底加哪一家比较好,该不该给公会做贡献,唯一的限制是 24 小时内只能换一次。

公会建筑的投资长期的效果是解开了游戏内对应子系统的上限。比如游戏里的工人,英雄,团队副本,甚至公会人数上限等等。系统分拆的非常细,连具体到数十个英雄中的特定一个的等级上限、能否参加 pvp 竞技场这些都分属在不同的投资对象里。

而这些小系统的升级本身只需要不断的玩游戏,经验就会增加,不需要金币。如果你的公会投资制造的天花板够高,没有触及你的上限,就可以很愉快的享受升级的乐趣了。

如前面的经济系统分析所言,游戏的市场活跃度非常依赖玩家的差异化发展,才会进一步有相互交易的需求。公会系统可以强化这点。因为对于玩家个人,他完全可以主导自己的发展方向;可放在一个几人甚至几十人的群体中,就很难完全按自己的想法发展了,更多的是适应(或者寻找更适合自己的团体)。尤其是陌生人为主构成的团队,公会的发展方向有更加不确定的随机性。公会投资用的金币是一个无底洞,没有人可以全部填满所有的坑。

如果投资只是为了集体利益(所有人的上限突破),一定不能良好的发展。所以游戏又在所有投资上添加了一个有时效性的增益。每笔个人投资都可以激活这个增益半个小时供全公会享用,同时个人获得一点即时的好处。这个增益时间可以叠加延长。

比如,生产铁矿的矿山。累积投资额决定了铁矿的基础产量;而每次追加一笔投资,半小时内,整个公会的铁矿产量可以再增加一个百分比;而投资人自己还可以额外立刻获得少量铁矿。

玩家在制造东西时,如果缺铁,他可以通过投资矿山买到少量铁矿使用,同时所有人在一定时间内产量都增加了。这项投资是越来越贵的,也就是单个铁矿需要的用金币计算的投资额会越来越高,越先投资就越划算,这就鼓励了个人投资。

再比如工人作坊,投资升级才能解开新的工人,以及提高已有工人的最高等级。而工人的技能等级决定了生产速度。累计投资水平决定了整个公会对某类物品的生产速度。而个人投资行为可以在短期加快这类物品的生产速度,同时个人可以直接获得工人的升级经验。

如果你倾向于制造武器,那么随着游戏过程,你会生产出越来越高级的武器。如果武器匠不升级,生产时间也会越来越长。这时你也就会倾向于把自己有限的资金投资在武器铺上,同时可以激活增益,让当下的武器生产更快。如果公会有人和你同时在线,他们也可以同时享受到快速生产武器的好处。

玩家只需要按个人利益来选择如何投资,不必考虑集体利益。但结果上有利于公会发展。这种不依赖游戏系统外的社交关系的公会系统设计,对于我这种喜欢自己闷头玩游戏的玩家来说,是相当舒适的。

在这个公会系统下,相近等级的玩家会自发的联合在一起。从我自己的游戏经历来看,我的公会有了空缺后,一天之内必然有差不多等级的玩家填入。而新玩家的加入立刻给公会带来了瞬间提升(他过去的投资被合并进来),给人的感觉还是很不错的。

由于公会人数也是从 4 人开始慢慢投资其中的建筑增加的,慢慢的公会成员会很珍惜名额限制,如果有死号离平均投资水平太远,就倾向于踢掉,腾出位置给更有价值的玩家加入。而投资很高的成员,会长是不敢轻易踢人的,否则会引起公会大量建筑降级(因为他会带走所有的历史投资)。

如果靠游戏外的社交关系而引入低等级玩家(亲友团)一起玩,对于这个低等级玩家来说,加入高等级公会是有利有弊。

有利的一方面是,各种等级限制都已打开,自己的各种系统都离天花板很远,可以舒心的慢慢玩,不用把紧缺的金币投资在公会里。而且如果和同公会的人一起在线,由别人投资产生的增益效果可以蹭到。

不利的一面是,建筑的投资费用已经远远超过了他自己等级的收入能力。无法再享受投资的立即好处。有些立即好处对发展是相当必要的:比如投资客栈可以让自己刷副本的时间成比例下降;投资主城可以成比例的减少升级家具的时间。这些时间在后期都是按小时计算的,非常影响发展速度。

总之,整个公会系统会鼓励活跃玩家自发的组织在一起。游戏规则引导玩家只需要去追逐自己的利益,不同的玩家在一起自发的形成公会的发展多样性,反过来影响了玩家的多样性。而有组织的公会,会因为人的协调而发展的更有效率一些,这会真正产生一些社交关系。

至于公会内的物品交互,公会 Raid 还有 pvp 对公会的贡献等,都是些锦上添花的系统,我自己也体验不多,就不做分析了。

Shop Heroes 的经济系统

最近两周在玩一个叫做 Shop Heroes 的游戏。知道这款游戏是因为它前两个月在 Steam 上线了 PC 版,玩了一下觉得有点意思。由于其 UI 一眼看上去就是手机风格,便在 app store 上搜索了一下,改到 ios 上玩。

游戏设计的很好,对我这种资深游戏玩家有莫大的吸引力(对于快餐手游氛围下进入的新玩家可能因为系统过于复杂而玩不进去)。它设计了无数个斯金纳箱,营造出文明的那种 one more turn 的心理感受,让人欲罢不能。具体不展开讲,有兴趣的同学自己玩玩试试。

让我感兴趣的是游戏内部的经济系统,经过数十小时的游戏体验,我隐约感觉的到设计者希望设计出一个以玩家交易税收为主体的商业模式。而这种模式很多人都提出(我从 10 年前就反复考虑,在 blog 上也做过一些思考记录)并希望实现,可全部都失败了。比如著名的 Diablo 3 ,曾经就宣称自己打算用交易税来维持游戏的利润,最后因为破坏了游戏体验而关闭了现金拍卖场。国内也有征途等打着以交易税为收入来源旗号的游戏,而实际上却只是个幌子。

而 Shop Heroes 似乎真正做到了这点。从结果上看,在市场上的中高等级玩家之间流通的物品全部是用钻石结算的。而游戏本身,玩家提交求购或售卖单的时候,都可以自由选择用钻石(现实货币)或金币(游戏货币)结算。虽然我是一个免费游戏玩家,但我尝试过用(免费获得的)钻石提单到市场,均快速成交,能感受的到市场的活跃。在这些钻石交易里,系统是要收取 25% 的交易税的。

我思考了好几天,游戏是怎么做到:引导玩家(同时包括 RMB 战士和免费玩家)进行钻石交易从而收税,这一点的呢?

其中一个关键点是:金币在游戏中其实是一种紧缺资源、而钻石才是市场上的真正货币。游戏并没有提供任何渠道作金币和钻石的兑换。大多数游戏中存在的直接购买金币,以及(直接或间接的)用钻石换金币的途径都没有。

游戏中从系统获得金币的途径主要就是制造出装备卖给 NPC ,虽然还有其它一些途径,但所在比例极少。换句话说,整个游戏生态中的所有玩家拥有的现金,全部是靠大量玩家不断的售卖制造品给 NPC 获得的。这个售卖行为可以看作出游戏中的第一产业,生产出来的产品就是金币,虽然金币也可以作为玩家中市场的流通货币使用,但从结果上看,中高级玩家间的订单很少是用金币进行的,原因下面会讲。

同时,游戏中玩家如果想升级,其经验的唯一来源也是售卖装备给 NPC 。注意,和前面的金币获得不同,这是唯一来源而不是主要来源。换句话说,只要玩家获得了经验,就获得了金币。所以,只要整个游戏社会的金币存量在增加,玩家的等级逐步上升是一个必然结果。几乎不存在其它游戏中的,不升级只生产钱的途径。

获得经验量是售卖给 NPC 装备的基础价的 20.5% 。玩家可以通过一些规则做一些上下浮动(讨价还价的玩法)但对结果并没有太大影响。

由于游戏的特殊设计,玩家升级并不是游戏的主要目的。游戏里还有很多系统(俗称的坑)需要单独升级,和玩家等级关系不大。但是少量重要功能的开启还是需要去升级的。比如同时雇佣更多的工人,制造更多种类的物品这些。而这些功能的开启,不仅仅需要等级上升,还需要消耗金币。

如果我们考虑一个中间级别 36 级(满级 50 级)。在这个级别,玩家只差最后一个工人槽位没有解锁,开启了几乎所有的游戏内容。之后,几乎没有等级上升的需求(但等级会因为不断玩游戏而自然上升)。

在整个 36 级阶段,必须的金币开销合计 2.7G ;消耗经验 130M 。也就是说,到 36 级的时候,玩家应该劳动所得 130 M / 0.205 = 634 M 左右的金币,但是有 2.7G 的金币需求。这之间有三倍以上的巨大缺口。

这还没有计算后面会提到的公会捐赠那个更大的金币黑洞。以及另外一个重头开销:升级家具和商店。

综合看来,社会对金币这种资源的需求量至少高出产量的 2 个数量级。


没有钻石直接兑换金币的途径,整个社会中发展慢一点(这里指整个社会,而不是玩家个人)来填补金币缺口也不做不到的,原因上面提到了,只要在掘金,经验随之而来,等级会自然上升。

整个社会如此缺少金币简直是必然的,这和玩游戏的人到底是免费玩家还是 RMB 战士无关。

那游戏的生态是如何保持的呢?秘密在于,高等级玩家的收入水平相较低等级玩家是成指数增长的。当你可以制造的装备高一等级,大约可以提高 1.5 倍的基础售价。而在玩家市场上,系统允许你最高标价 10 倍之基础售价来贩卖你的物品。也就是可以把一件物品的售价提高到超出 5 个装备等级的基础价格上。

如果一个玩家可以选择在游戏中的 25 类物品中的某几个单类上进行突破,制造出自己等级并不适用,但适合高出自己 5 个玩家等级的玩家阶层需要的物品,那么他们就能获得 10 倍金币收益了。(注意:最近游戏的更新中,直接限制了玩家在市场中不可见 5 级玩家等级差以外的物品)

换句话说,低等级玩家通过给高等级玩家打工,满足了金币需求。而一层层推到金字塔顶,顶级玩家对金币的需求会变小。

无论如何,金币永远是稀缺资源,而游戏规则又制造了大量玩家间的买卖制造品的市场需求,尤其是同级玩家相互售卖;以及低级玩家去买高级玩家的制造品的需求(出不起高级玩家期待的金币数量);最终会导致市场上必须使用另一种货币,钻石就自然成为了硬通货。

钻石作为通货,系统存量是由 RMB 战士购买投入的。游戏卖的好的话(充值多),就会通货膨胀;卖的差,就会通货紧缩。但它只会影响玩家市场上的商品标价,对其它游戏部分并没有冲击。游戏系统对免费钻石的投入非常有限,集中在游戏内广告观看,对游戏厂商而言,应该也是一笔直接收入。

钻石除了作为通货,也可以向系统购买一些服务,这些服务的售卖制造了不太参与市场交易的玩家对钻石的需求。不会对经济系统造成影响。比如:升级制造槽,可以简化多段制造装备的流程;升级冒险槽,可以简化英雄刷副本的流程等等。这些表面上看是在贩卖一些“不影响游戏平衡性”的绿色消费,但深层次上说,这些服务几乎和上面提到的金币有关的游戏系统无关,维持了经济系统的平衡。


最后简单谈谈游戏是怎么制造出玩家不断生产商品出来贩卖,以及为什么玩家间有大量交易需求的。

和很多同类商业经营类游戏不同,很多同类游戏中,每个玩家可以制造的物品几乎是相同的。

而这个游戏用工人技能限制了玩家可以制造 25 类物品中的某几类,虽然可以通过解聘工人再聘用新工人来完成制造技能的切换。但一则操作繁琐,二则在后期更换高等级工人需要消耗大量金币,最终变得不太可行。

而玩家在游戏过程中,又几乎需要所有的物品,当自己只能制造一部分时,就必然有和其他玩家交易的需求。

物品的制造资源分两类,基础资源是依靠时间直接获得;而另一种稀缺资源必须用英雄下副本刷出来。副本战斗需要英雄有一定的战斗力,而战斗力是靠装备堆出来的。游戏中装备破损率的设定,导致了没有装备是可以一直用下去的,不想别的游戏中,只有升级才是更新装备的动力;在这个游戏中,装备真正成了消费品,即使英雄一直停留在一个等级,也不断有装备需求。

另外,PVP 竞技场的存在更是促进了玩家对高品质装备的追逐。

这部分游戏系统设计的非常精巧,以上只是点出大概,而它其它环环相扣的设计必须自己游戏方能体会。


下次,我还想谈谈 Shop Heroes 里独特的公会设计。他的公会系统和传统的国产网游不同,不依靠游戏外的社交关系联系,而几乎全部围绕游戏内的利益关联。可以促成活跃玩家在同一个公会游戏,并让相近游戏进度的玩家自发的联合起来。我觉得还是满有趣的。


最后,我想说,我玩这个游戏还不算太深入,人物等级也才 24 级,只能算初级水平。所以以上的分析可能和真正情况差距较大。只能算是我自己的一些思考,作为以后自己的产品的一个设计参考吧。