百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

开发笔记:游戏中抽象物品模块接口设计

haoteby 2025-05-08 18:30 12 浏览

抽象物品这个词汇是我为了说明方便生造出来的,用于指代游戏系统中任意可以附加于玩家的东西,比如金币、宝石、经验、道具、英雄、宠物、装备、积分、体力等等,都可以用通用抽象物品接口来替代。其实抽象物品几乎所有游戏项目都在用(至少我接触过的项目都有),只是没人去正经的归纳。

数据结构

这个东西说白了其实就是一个union,里面包含了可能的各种数值和数据,当然了因为是unoin嘛,其中只有一部分会起作用。这里给出我们项目中使用protocol buffer定义的数据结构。

  1. message CommonItem {

  2. enum Type {

  3. Property = 1; //数值

  4. BagItem = 2; //背包道具

  5. Hero = 3; //英雄

  6. //...

  7. }

  8. optional int32 type = 1;


  9. message PropertyData {

  10. enum PropertyKey {

  11. Gold = 1; //金币

  12. Gem = 2; //宝石

  13. Exp = 3; //玩家经验

  14. //...

  15. }

  16. optional int32 key = 1;

  17. optional int32 count = 2;

  18. }

  19. optional PropertyData propertyData = 2;


  20. message BagItemData {

  21. optional int32 id = 1;

  22. optional int32 count = 2;

  23. }

  24. optional BagItemData bagItemData = 3;


  25. message HeroData {

  26. optional int32 id = 1;

  27. optional int32 level = 2;

  28. optional int32 star = 3;

  29. }

  30. optional HeroData heroData = 4;

  31. }

嗯,看上去还是挺复杂的。CommonItem包含了一个type字段指明了该抽象物品的具体类型,后面是各种具体物品携带的数据,可能是玩家的某个属性值,可能是背包、英雄等,注意我们使用了optional选项。 当然了,也可以直接记录几个数字,第一个数字代表类型,后面几个数字的意义由类型来决定。也有直接用带分隔符的字符串来表示的。原理上来说都是类似的,我觉得使用protocol buffer进行结构化的表示更加直观一些。

为什么做抽象

上面也说了,这个结构是比较复杂的,而且构建和解析也会比较费劲,那么我们为什么折腾出这么个东西呢。主要有下面几个原因:

1. 解耦各个模块

当系统中一个模块调用另一个模块时,就产生了依赖,依赖无疑是需要我们竭力减至最小的。注意到两个模块间调用时大部时候都是在修改彼此的数据,更进一步,大部分的数据修改都在添加或消耗某些东西。比如副本掉落道具添加进背包,打副本时消耗体力,完成任务时添加经验和金币。

假如副本能同时掉落金币、经验、体力、背包物品,那么副本就同时依赖这些模块,也就是说这些模块中任意一个的接口发生变化时,我们就不得不修改副本模块的代码。再来看背包,副本、任务、宝箱、商店都会改动背包的数据,所以这些模块同时依赖于背包模块,所以如果我们改动了背包的接口,这些模块的代码都要修改。

很显然,这里是一个很不合适的M*N的关系。所以我们需要加一个分发模块作为“中介”,抽象物品作为“载体”。所有的调用模块都只依赖分发模块,它们只需要知道需要添加或消耗抽象物品,而不关心具体维护对应数据的模块。分发模块负责将抽象物品分发到不同的数据模块。这样一来M*N的关系就变成了M+N。

2. 配表更加灵活

就拿副本掉落举例子。如果没有抽象物品,当策划想让副本掉落金币时,可能会在表里加一列,定义为金币。等过了几天想换成掉经验,于是通知程序修改代码……又过了几天觉得还是换成背包物品比较好,于是又多加了几列,再通知程序修改代码……更杯具的是,如果到后期新开放了积分系统,好多配表都需要添加积分这一列。这样显然不是很灵活。

如果有设计恰当的抽象物品,很多产出和消耗都可以配成抽象的物品,策划可以很灵活自由地修改数值。程序这边也很方便,只需要写一次解析抽象物品配置的代码。

3. 方便交换数据

例如抽卡功能,服务器需要把抽出的结果返回给客户端显示,这时直接使用抽象物品这个数据结构来交换数据,定义消息接口时不用关心具体产出物品的类型。 另一方面,不管抽象物品实际是金币还是背包物品或是能量,客户端总是要以相似的形式在界面上显示出来:常见的一个图标、图标下方有物品的名字、图标的右下角是数量。有了抽象物品这个结构后,只需要正确处理好对抽象物品的显示,所有系统的界面都可以直接调用了,而不关心那个系统所要展现的具体是个什么东西。

分发模块设计

分发模块上文已经大略介绍过了,可以简单地理解为一个代理,其功能是把对抽象物品的操作映射到对实际数据的操作。

分发模块主要定义这三个接口:

Add(CommonItem) 添加一项抽象物品

Remove(CommonItem)删除一项抽象物品

Has(CommonItem) 判断玩家是否拥有一份抽象物品

另外一个要解决的问题是,有的数据不是直接附加于玩家本身的,比如英雄经验应该附加于某个英雄上,技能经验应该附加于某个技能上,等等。所以我们在添加一项抽象物品时,可能还需要一些额外的上下文数据(英雄id,技能id,宠物id等),这些上下文数据应该是触发操作的环境中可以获取的。例如对于打副本,上下文数据中就应该包含当前出战的英雄,副本模块应该负责将自己的上下文数据告知分发模块,以供其正确分发。

所以最后分发模块的接口这样定义:

Add(CommonItem, Context) 添加一项抽象物品

Remove(CommonItem, Context)删除一项抽象物品

Has(CommonItem, Context) 判断玩家是否拥有一份抽象物品

其中Context中包含由调用者感知的上下文数据。可能的问题是:如果数据配置有总是,当发现要添加的抽象物品是英雄经验时,上下文数据中并不包含英雄id(可能是开宝箱触发的),那么此时无法正确添加。坦率地说,这种问题现在想不到好的解决办法,这也是抽象统一接口所带来的代价吧!

相关推荐

网站seo该怎么优化

一、网站定位在建设一个网站之前,我们首先要做的就是一个网站清晰的定位,会带来转化率相对较高的客户群体,我们建站的目的就是为了营销,只有集中来做某一件事,才会更好的展现我们的网站。在做SEO优化的同时...

3个小技巧教你如何做好SEO优化

  想半路出家做SEO?可是,怎么才做的好呢?关于SEO专业技术弄懂搜索引擎原理,咱们做搜索引擎排名的首先就是要了解搜索引擎的工作原理,对SEO优化有更深入了解之后再来做SEO,你就能从搜索引擎的视点...

SEO指令分享:filetype指令

filetype用于搜索特定的文件格式。百度和谷歌都支持filetype指令。比如搜索filetype:pdf今日头条返回的就是包含今日头条这个关键词的所有pdf文件,如下图:百度只支持:pdf...

网站seo优化技巧大全

SEO在搜索引擎中对检索结果进行排序,看谁最初是在用户的第一眼中看到的。实际上,这些排名都是通过引擎的内部算法来实现的。例如,百度算法很有名。那么,对百度SEO的优化有哪些小技巧?下面小编就会说下针对...

小技巧#10 某些高级的搜索技巧

由于某些原因,我的实验场所仅限百度。1.关键词+空格严格说来这个不能算高级,但关键词之间打空格的办法确实好用。我习惯用右手大拇指外侧敲击空格键,这个习惯在打英文报告时尤其频繁。2.site:(请不要忽...

MYSQL数据库权限与安全

权限与安全数据库的权限和数据库的安全是息息相关的,不当的权限设置可能会导致各种各样的安全隐患,操作系统的某些设置也会对MySQL的安全造成影响。1、权限系统的工作原理...

WPF样式

UniformGrid容器<UniformGridColumns="3"Rows="3"><Button/>...

mysql自动备份,并zabbix检测备份文件是否正常,备份文件大小

推荐...

MySQL学到什么程度?才有可以在简历上写精通

前言如今互联网行业用的最多就是MySQL,然而对于高级Web面试者,尤其对于寻找30k下工作的求职者,很多MySQL相关知识点基本都会涉及,如果面试中,你的相关知识答的模糊和不切要点,基...

jquery的事件名称和命名空间的方法

我们先看一些代码:当然,我们也可以用bind进行事件绑定。我们看到上面的代码,我们可以在事件后面,以点号,加我们的名字,就是事件命名空间。所谓事件命名空间,就是事件类型后面以点语法附加一个别名,以便引...

c#,委托与事件,发布订阅模型,观察者模式

什么是事件?事件(Event)基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些提示信息,如系统生成的通知。应用程序需要在事件发生时响应事件。通过委托使用事件事件在类中声明且生成,且通过...

前端分享-原生Popover已经支持

传统网页弹窗开发需要自己处理z-index层级冲突、编写点击外部关闭的逻辑、管理多个弹窗的堆叠顺序。核心优势对比:...

Axure 8.0 综合帖——新增细节内容

一、钢笔工具与PS或者AI中的钢笔工具一样的用法。同样有手柄和锚点,如果终点和起点没有接合在一起,只要双击鼠标左键即可完成绘画。画出来的是矢量图,可以理解为新的元件。不建议通过这个工具来画ICON图等...

PostgreSQL技术内幕28:触发器实现原理

0.简介在PostgreSQL(简称PG)数据库中,触发器(Trigger)能够在特定的数据库数据变化事件(如插入、更新、删除等)或数据库事件(DDL)发生时自动执行预定义的操作。触发器的实现原理涉及...

UWP开发入门(十七)--判断设备类型及响应VirtualKey

蜀黍我做的工作跟IM软件有关,UWP同时会跑在电脑和手机上。电脑和手机的使用习惯不尽一致,通常我倾向于根据窗口尺寸来进行布局的变化,但是特定的操作习惯是依赖于设备类型,而不是屏幕尺寸的,比如聊天窗口的...