手游框架设计<二>

2015年09月26日 11:16 0 点赞 0 评论 更新于 2017-05-02 16:16

静态数据(配表数据)

在完成数值和数据的配置后,是否需要为每一份配置表编写一次解析代码呢?静态数据的设计主要涉及两个方面的人员:一是设计人员,通常为策划;二是使用人员,一般是程序。对于策划而言,Excel 是最为理想的工具;而对于程序来说,CSV 是性能较好且易于解析的格式。当然,也存在将 Excel 导出为 XML 或 JSON 的情况(个人比较反感 XML)。

常见方案

常见的做法是,每当策划新增一份配表,程序员就需要为该表编写一份专门的解析文件,并为表数据定义数据结构。例如:

struct HeroItem {
int hp;
int atk;
};
typedef std::vector<HeroItem> HeroDB;
void parserHeroDB(const char* buf, HeroDB& db);

改进方案

下面介绍我的方案,通过与策划约定一种方式,程序无需编写解析代码,直接使用数据即可。例如:

print(DataPort.HeroDB[heroId][lv].hp)

这个示例展示了如何查询配表中某个 heroId 的英雄在 lv 等级下的血量。

实现方式

关键在于设计一张描述其他表的表,以此告知解析器如何加载这些表。具体而言,解析器需要了解以下信息:

  1. 数据类型:每列数据的类型,我将其分为 4 种:数值、字符串、数值数组、字符串数组。
  2. 索引建立:每一列数据所属的字段,明确哪个字段作为 key,同时考虑支持三维表,即增加一个 subkey,一般情况下这就足够了,并且应限制最多为三维,因为维度过多往往意味着设计存在问题。

设计 data_list.csv 表来描述 hero.csv 的解析方式,示例如下:

data_list.csv

idfile_namemain_keysub_keydescript
HeroDBhero.csv

hero.csv

idlevelhpatk
111013
121114
131215
21205
22225
23245

其中,data_list.csv 中的 descript 里的 0;0;0;0 表示“数值;数值;数值;数值”,恰好对应 hero.csv 中一行数据的解析方式,这里用 0 表示数值解析。

有了上述约定,我们就能够轻松编写一个解析器来完成数据的解析,解析后将数据赋值给 HeroDB,这样就可以直接从中获取数据了。

方案优势

这种做法的优势十分明显。由于数据表经常会发生变动,如果采用常见的方案,每次变动都需要修改数据结构、解析代码以及相应的逻辑,过程极为繁琐。而将这些变化交由导致变化的策划人员自行处理,能够避免浪费程序员的宝贵时间。

作者信息

洞悉

洞悉

共发布了 515 篇文章