您需要 登录 才可以下载或查看,没有账号?注册
x
最近对外交流比较频繁,接触了很多朋友的项目,发现在他们的项目中,数据表的建立都有比较大的问题,大多表现为:
1,数据列众多:随机挑张表打开一看,我的天,横向没有100列也得有5、60列,做个页游甚至手游,至于吗?但是他们却能详细的分析出每一条打算干嘛?这点我觉得至少他们都是做过项目的老团队,分析出这些数据的作用应该不难,但是却让我看到了一些问题——策划与程序的沟通缺乏,甚至有些团队的表结构是由程序建立的,而程序员本身对游戏即将做成什么样也是一知半解。
2,表连表频繁:一个任务表,某几列挂向NPC表,为的是谁给的任务,任务交给谁,还有任务过程中要接触谁(比如杀什么怪);除此之外,还要挂向道具表,任务奖品、任务掉落等;这还不够,他还要挂向一些其他表,比如buff表,技能表。我的天,这你让策划怎么去填这个表,天地良心,一个公司机器配置最差的基本都是策划,而他们却要用这种机器打开高配机器开了都吃力的这么多的表,仅仅只是为了填一个表。
我相信大家经历的项目中,以上两大问题,多多少少都会遇到过一些吧,从我的经验来看,在一个游戏设计师设计表的时候(我认为数据表结构应该由策划提供),需要注意以下这些,才能建立出比较适合的表来:
1,合理利用计算公式、巧妙运用数据类型,该去掉的去掉,该合并的合并。
么是合理利用计算公式?我见过很多混账表,其中甚至包括了玩家升级经验表,这往往发生于那些认为策划应该被细分为系统、数值等工种的团队。事实上在经验值的数值设计上,是最开放的,在你设计整个游戏系统的时候你想要的经验值提升曲线如何?无非越高等级需要越多经验,这我们都知道,那么经验增长速度的环比如何?无非也就是越到后面提升越慢的和越到后面提升越明显的,2个都接近于公式y=power(a,b),区别在于前者的b要大于1而尽可能小于1.5,后者只要大胆的大于等于2就好了,这至于去填一个表吗?不值得!这就是所谓的该去掉的去掉,某列数据可以用公式计算,或者通过其他数据演算获得,那么就去掉它,表的每一列数据都应该是独特的,是计算机无法通过一种固定逻辑产生来的,因此才需要人为去填写。
什么事巧妙运用数据类型?我见过一些技能表,在不断地开发过程中无限膨胀:今天策划想出来了某某技能不能对建筑物使用(dota类),由于表是程序建立的,程序说了,加一列“可否对建筑有效”,布尔型;明天策划又想到了,一些技能还不能对元素类别的怪物使用,于是程序又说了……逐渐逐渐的,表列越来越多了。你可以说策划初期为什么没有想好有哪些目标类别,那这样一早建立好表,不就不用去改了吗?事实上有经验的项目经理都知道,这是不现实的,因为人每天都在思考,新的主意如果够好,应该被利用。那么像这样一个动态性的问题,事实上我们可以把它变成一个位运算的做法。每一个角色数据中有一项免疫类别(ImmuneType),而技能本身有一项效果类别(effectType),我们指定元素类为0位、建筑为1位、魔法为2位、诅咒为3位、钢铁为4位,这些都是我现在脑袋一拍说的,明天策划说了我又有技能不能对昆虫类用,没关系,昆虫为5位,用一个int64来记录该项我觉得足够了,但使用string就有些亏了,我不信有策划能想出64个特性来。而实际工作中,策划只要为元素建筑物单位的免疫类型配置为3(1左移0或1左移1,这句话不能用语文的方式理解,而要用程序的方式),钢铁元素建筑19就可以;而我们有一个火球技能为元素魔法那么他的效果类别就是5,刀砍技能没有符合以上的特效他就是0。而在程序处理过程中,判断技能是否对目标有效的函数也比多条if好些很多,直接return (skill.effectType | guy.ImmuneType)>0; 就可以返回是否免疫了,如果是true就是免疫。如此一来原本可能扩展为64列的数据在1列中就概括完成了,事实上除了位运算外还有挺多其他的细节技巧可以运用,不妨开动自己的脑筋利用学到的知识好好想想,实际问题用实际的解决方法对付。
2,加权值好过百分比。
在WoW流行了这么多年后的今天,受尽了WOW熏陶的很多策划,他们往往也看过不少WoW的数据库,因此他们对于掉落的理解仅仅限于XX的掉落率为yy%,然后设计掉落表的时候,简单的要求了我填写掉落百分比。好吧,这就引发了一个问题,你填写的百分比是干什么的呢?比如哥布林5%几率掉落斧头,12%几率掉落桔子?这个还好说,因为综合没有超过100%,如果哥布林还有80%的几率会掉落哥布林卡牌,这时候程序该怎么办呢?for循环遍历他所有会掉的东西,然后达到掉落概率就掉?策划会说可能会掉太多,那么while不掉do random next?策划又说填写的越前面的掉率越高不符合想法,当然是事也是如此。程序听完毛了,那好吧,你在增加一个不掉落率,然后保证掉落率总和+不掉落率=100%。事实上这是一个极为愚蠢的做法,但很典型,的确它能解决眼下的问题,当时当策划明天认为哥布林还会掉落头盔的时候就麻烦了,必须去修改已经填好的所有内容的概率。因此在这里我推荐大家还是采用加权的做法,至于掉落系统,各个游戏不太一样真不好说,但是加权的做法是针对每一系掉落的,比如我有一个怪,他一定会掉落列表中的某个东西,只是概率不同,这样一个系统,我只需要为每个掉落配一个加权:巧克力20,咖啡11,橘子122,饼干7,那么按照之前系统设计来看,他掉落巧克力的概率就是20/(20+11+122+7)=12.5%,当加入新的掉落香蕉40的时候,巧克力的掉率自然就降低到了10%,而不需要策划手动去更改。
3,利用Tag机制,让执行者有更多的预判断而不至于陷入死循环。
现实开发中,我们经常会遇到填表的时候表连表,这是不可避免的,即使设计的再好的表,他也会至少挂向别的一个表,此时我们会遇到一些问题——我设计了软泥怪,它会掉落公主的靴子和猪头怪的獠牙,可是道具表还没有填,我也不知道这俩道具最后id会是多少。可是道具表里面某些道具使用后才能产生软泥怪……这样一来,事实上陷入了一个很常见的僵局,表A没完成弄不了表B,而没有表B,表A也高不了……
这里我推荐大家一个做法就是Tag机制,对于每一个需要表表连接的地方,都采用一个tag模式而非直接id模式。什么是tag模式?简单的来说,还是上面这个软泥掉落道具的例子,我们可以为每个道具设定一个tag,这个tag是Array<String>的,也就是说他有多个字符串tag,策划可以为公主的靴子配置tag为"dropbyslim","soldbygoblin",而为猪头怪的獠牙配置tag为"dropbyslim","food003","chocolate"等,由于软泥怪的掉落套组中包含了"dropbyslim"这个标签,因此这两个道具都会成为他的掉落品,因为他们都含有这样的tag。
Tag机制的可以说是缺陷的地方在于,如果你直接将tag概念引入到最后的游戏的逻辑程序里面,这会产生效率问题,因此最好还是在数据表变成程序可读的数据表的过程中,由转换表的程序来实现一个遍历转换,将他们变成id式连接。我们公司使用的工具中,我已经加入了这个逻辑,大家不妨推荐程序这么做,这样会很好的避免策划将时间浪费在改表上。
以上是一些我在建立数据表时候的Little Trick,我觉得可以share给大家一起讨论下,看看优缺点,或者和你们现在的方式结合是否能产生更好的做法。但如果你只是一个新手,想学习如何建好表,想知道从哪儿学起,我的建议是,学着去修改单机游戏的存盘文件,那里有老一代游戏制作者对于数据结构的归纳心得。 |