« Lua 5.2.1 的一处改变 | 返回首页 | 开发笔记(23) : 原子字典 »

开发笔记(22) : 背包系统

我们项目的第一个里程碑杯已经比较顺利的完成了。主要是完成最基本的用户注册登陆,场景漫游,走跑跳,远程进程法术等技能攻击,怪物及 npc 的简单行为,等等。尝试了几十个玩家与上百个 npc 的混战,还比较流畅。

中间小作休整,然后开始做第二里程碑的计划安排。这次预计要三个月,完成几乎所有的 MMO 必须的游戏功能了。

其中一个大的任务就是要完成背包、物品、装备、货币、掉落、交易这些相互关联的模块。

下面简单记录一下背包系统的设计实现思路:

我们希望可以追踪每件可能被交易的物品,每件物品都有 64bit 的唯一 id 。在背包格里可以叠加若干件相同物品,但是每件物品都有单独 id 。这个 id 是用于最终和拥有者校验用的,不必传输给客户端,在交易系统外也不需要被读取。

最终,定了三个概念:背包( BAG )、仓库( STORAGE )和物品( ITEM )。

物品包括了装备,但不包括货币(只追踪数量不记录每个单位的 id 的东西,可以放在背包里,也可以独立列出)和任务物品。这里任务物品可能被放在背包中,并可以移动位置。但不可以被交易,不用记录物品 id ,它其实是一种任务进度指示器。

仓库保存了玩家所有拥有的物品,每个玩家只有一个仓库,仓库里每个格子只能存放一件物品,不可以叠加。只可以向仓库添加或删除物品,不可以交换位置,也不可以指定格子存放。实际上,仓库只是用来辅助物品追踪,确定物品所有权用的。

背包是玩家所有,存放所有物品以及任务物品和货币的容器。一个玩家可以拥有多个背包,装备栏、银行仓库等都是用背包来实现的。背包格里可以叠加存放多个相同物品,也可以用来存放货币或任务物品。

物品是以 lua 对象的形式保存在内存中的,不同类别的物品有不同的方法可以获得物品的不同属性。我想以一个类别名加一组构造参数的方式来持久化物品对象。

比如大多数游戏内的物品只需要用“物品”和“名字”来唯一确定一种东西。“物品”是它的类别名,它只需要有一个构造参数就是“名字”。具体的物品等级、交易价格、详细介绍等等,都是通过这个名字可从策划填写的表格中检索出来。当然这里也可以不是用“名字”,而是“类别 id ”。从这个 id 进一步检索出物品名也可以。

装备更复杂一些,光有一个名字还不能构造出来。它可能还有随机附加属性等参数。这里有一个小技巧,可以只在构造参数里记录一个随机种子,在构造过程中,利用这个种子构造出多个随机量。

还有更复杂的特有装备,比如玩家制造的装备,需要记录下装备制造者的名字。或是有用宝石强化过的装备,需要记录强化信息。

大原则就是,用类别和绑顶在类别上的参数,可以唯一表达出这个东西是什么。类别用字符串表示,对应相应的对象构造脚本。

装备对象至少要提供一个方法,可以把内存中的对象再次序列化为类型名于一组构造参数。

清楚的定义出装备的概念,以及表达方法后,我们就把装备模块和背包以及交易模块分离了。

背包系统直接用先前开发的共享储存系统 映射出来。但在实现时,还额外为每个物品格附加一个域存放物品对象。在每次加载后,都利用物品类别名和构造参数构造出物品对象来。运行过程中,都是用这个对象来完成物品相关的操作。

每个背包格里都只能有一个物品对象,但可以引用多个仓库格,以示叠加。交换两个背包格不会影响仓库的内容,只是索引交换一下。但是,如果背包格里的对象不存在于仓库中时(可能是任务物品,也可以是某种特殊货币),就需要在移动物品时,重新在目标格序列化物品对象。

我们并没有专门去做玩家数据存盘过程。所以一直保持所有需要存盘的内容都放在共享储存系统里是很重要的。只要有需要,随时都可以从另一个进程来读取并持久化它们。至于在边界情况下可能造成的物品复制问题,则由交易系统去保证。

背包有几个基本操作:

  • QUERY:查询一个物品格里的物品对象和数量。
  • TRADEOUT :把一个物品格里的所有物品都拿出来。生成一个交易单。这个 API 主要是把物品从背包里抹掉,如果物品格对仓库有引用,也同时抹掉。返回的交易单是一组纯数据,里面有物品的序列化信息,以及所有的物品唯一 id 。
  • TRADEIN :把一个交易单里提到的所有物品,合并到一个物品格里。这个是 TRADEOUT 的逆操作。
  • EXCHANGE :交换两个物品格。
  • SPLIT :把一个物品格内的多件物品分割成两份,放在新的格子中。
  • CONSUME :消耗掉一个物品格中的若干件物品。

这里提到一个新概念,就是交易单。交易单上记录了一批物品,是物品的序列化信息,以及这些物品的 id (如果有 id)。这个交易单可以很容易被跨进程传输到交易或掉落系统里去处理。交易系统和调用分配系统都会使用这个数据结构做数据交换。

Comments

恩,在游戏中对于叠加的物品只是认为是一个实体,这样以后的确不好追踪玩家行为,多多少少会出现一些问题,对于玩家的对物品拆分,叠加,交易等操作后,没有很好的追踪办法了。


就是不知道作者为什么把这个叫做仓库,是数据仓库之意吧?

汗,为什么会这么复杂?

@limantian
128位是可以保证随机分配ID的唯一性,但对于使用计数器分配ID来说,64位足矣

id不如直接使用128位的uuid,虽然多了64位,但是能保证唯一性,可以在很多方面简化问题

远程进程法术等技能攻击==>近程

我想知道游戏的名字.关注好久了

“仓库”这个名字感觉不好,容易和游戏中“寄存物品的仓库”搞混,可以换个贴切的名字。

回楼上,"实际上,仓库只是用来辅助物品追踪,确定物品所有权用的"

这个仓库是游戏中的仓库的概念吧,不明白为什么不可以交换位置呢?

Post a comment

非这个主题相关的留言请到:留言本