|
咳咳咳....
那个啥,这次重新入坑GE,因为过去几年在代码这方面有小小的进步,所以这次就直接从Galaxy玩起了.
昨天花点时间看了头目写的关于Galaxy的教程,今天早上被前辈们喷过之后,总算是把WE里面的字典树给翻译成能用的Galaxy了.
字典树这玩意是个什么鬼么,理论解释请戳传送门,我就说说这鬼在WE时代的用处...(毕竟我刚刚从WE坑出来,还饱蘸着旧时代的腐朽气息,前辈大大们要指点我会以抖M的心态好好享受的~ V ~)
WE时代比较头疼的一个问题,不管是用T还是用J都存在的吧,就是这个元素集合的匹配——
元素集合就是指若干同类(多数时候)或者不同类(....)的元素组合成一个元素集A,而事先游戏的数据库中给出了一些特定元素集的释义,匹配的意思就是在这些存在特定释义的元素集是元素集A的非空子集时,将对应的释义提取出来然后拿来做点什么....
好吧,这么说还是抽象,接下来我用War3时代的东西罗列一个表格来举几个栗子,大家具体地感受一下.========================================================================
对于知道是怎么回事的看官,你们无视下面这段废话就好...
| 元素范畴 | 元素类型 | 释义元素集 | 释义(结果) | 物品合成 | 物品 | 整数 | 合成配方 | 合成产物 | 技能ID鉴别 | 技能Id | 整数 | 触发响应的技能ID | 相关触发动作 | 单位ID鉴别 | 单位Id | 整数 | 特定的单位类别ID | 相关触发动作 | 游戏命令 | ASCII字符 | 字符 | 具有特定功能的聊天消息 | 命令响应动作 |
我的意思就是想说什么呢,传统的触发器动作包括脚本命令,都是以元素或者集合整体为检查给定的元素集A是否含有在某个领域上被注册过的元素集合,这个表格里面的内容在做图的时候会变成以下更具体的现象:
1.物品合成一共有m个容量为n的配方,每个配方包括材料和各种材料的数量,为了搞清某单位U的物品栏里面有a个材料的时候,能够合成哪些物品,于是传统的枚举算法依照配方材料表对容量为k的物品栏做遍历,情况最糟糕的时候运算次数N=m*n*a.
以魔兽时代的物品栏6格限制为例,n和a最多是6*6=36,这还不错,然而每多增加一个新的配方就使合成一次检索的最大检索次数增加36.即使是dota那样支持一个满格合成,一个配方的代价也是42.
这种枚举遍历最容易实现,但是问题也挺大,
1.配方数变多或者配方变复杂都会缩减最大容纳的配方数量,而且降低效率.
2.考虑dota那样一体多形的物品系统下,如果不做点加工,运算次数还要额外乘上一个形态数量遍历系数f.
到了SCII里面,撇开上面的问题不谈,我们稍微做个有点内容的rpg,可以轻松愉快地弄个6*6,8*8的背包再加个8,9格的物品栏,这时候枚举的代价就有点可怕了,每新增一个配方可能意味着几百次额外的检索,这要是做个内容稍微复杂点的rpg可能会把机器配置不好的童鞋们卡得死机...
2.技能Id/单位Id
魔兽时代就有过通魔技能通过工程升级得到改动了物编数据但是触发效果一致的新技能在触发器被识别的这种问题,当对应同一套触发内容的技能Id较少的时候,直接用条件检查很快捷,但是当这类技能变多的时候,就会先考虑用数组对其加以记录,然后用捕获的技能Id做枚举,这么做对效率产生的负面影响比起物品合成要小得多,但是用来记录技能id的数组确实麻烦.
至于把技能做命令按钮,根据技能Id激发具体效果不同但是又公用主体函数的情况,枚举往往带来了不必要的参数和代码.
3.游戏命令
这个问题其实就是类似dota中"-swap","-swap #"和"-swapall"这三个游戏命令直接细微的差别一样.
制作rpg的时候往往会定义一些命令,有些命令虽然功能不一样,但是构造上大同小异.
可是触发器中鉴别命令的时候,往往是将整个命令与事先定义的有效命令加以比对,再执行对应的行为.
但是为了查询一个命令是否有效,就不得不把一些废话也视作"潜在有效"的命令来逐个遍历游戏指令集合,虽然可以用模糊筛选除掉一部分内容,但是就像dota游戏命令都以"-"为前缀,所有以"-"开头的废话还是会被当成可能有用的命令来遍历指令集合,在游戏指令不多的时候这种废话无关紧要,但是当我们的图有上百个指令的时候,一句类似"-fuckme","-gobacktoitaly"这样的废话可就要拉上无辜的玩家一起享受恶作剧者的恶趣味了...
对于知道是怎么回事的看官,你们无视上面这段废话就好...
========================================================================
所以栗子举到这,大家应该都懂了,上面这些麻烦和隐患肯定是该想办法避免的.
而引起这么多麻烦的原因就是对一个问题,元素集合的匹配,的更好的解决办法,或者说算法吧....
这个办法就是字典树.
关于字典树我不想在此多加赘述,它的实现原理就是把"对着字典整个整个查单词"这种不人性的算法优化成"按照单词拼写顺序逐个查字母"的算法,而代码上的具体实现也就是将词典和单词的规则联系搬进Galaxy中,而具体的实现结构,我用的是数据表+数组引用.首先建立一个字典树的目录规范,这主要是一些建立数据表字符路径时使用的前缀字符串,为的是让字典树结构的数据整齐,便于建立和查询.
string Trie_RootName="Trie-"; //根目录
string Trie_Child="-Child-"; //子级前缀,用于放置在一个查询序列的后方,加上下一个节点元素构成子节点可用性目录,并从该目录下读取布尔值,当值为真时说明链接可行则继续向下搜索.
string Trie_Result="-Res-"; //结果前缀,当查询到最后一个元素或者某一元素之后所有的剩余元素无法和现有序列生成可行链接时,在当前序列后追加该链接取该序列下的结果.
string Trie_UsedResult="-ResSize-";
//结果数量,字典树中的一个特定序列往往会对应多个不同的意思,当两个序列完全相同却在不同搜索条件下要求不同结果时,则产生"一词多义",该目录下的值用于记录特定组合的多义数目
string Trie_ConjSymbol="-"; //衔接间缀,字典树查询序列在尾部增加新元素时,在新元素和原序列之间插入该标记以指示查询轨迹,便于测试时检查.
int Tire_ResultInd=0;
//字典树配义数,因为这个字典树中具有同一个值的节点唯一,这就需要划分同一条查询序列的不同释义,为某个使用字典树功能的模块分配一个释义Id,则以该Id为查询标记的所有序列皆取可行结果中以此Id标记的值,而这个整数只增不减.
然后是数据的统一规范,一般而言字典树会用在查询整数序列和字符串序列上,而整数和字符串在Galaxy里面是两种不同类型.
但是为了一个字符串去制作另一种规格的字典树么?
所以我用一个字符-整数的互转库,将字符串转换为ASCII的整数编码,从而把字符串序列化归成整数序列,但缺陷也有,就是只支持英文标准ASCII字符串,所有其他字符都会被转换成"0".
然后是一套用于处理有序字符串信息的函数组,用于以更加灵活的格式传递有序参数,根据解码函数的不同,可以传递内容不同的字符串信息,这功能可以简化记录物品配方或者物品属性时的参数结构
但是这里不多说了,具体可以参见这个帖子:
关于这两天对自定义循环函数的研究以FOREACH为例
这个很老的帖子中提供的方法在今天也很有实用价值,或者说我的字典树是这个帖子的实践也不为过.
尽管其中使用的方法远早于我,但是我在这个方法的基础上对其进行了发展和提升,参数传递的自由度更高,字符串参数组的可读性也更好些.
因为我是在转写自己War3时代的底层代码,所以没有做成Demo图,这里直接发Mod上来,可以把Mod和一张具体的图挂接起来看效果.
Mod里面示范了基于聊天信息的字符串字典树的组建和查询,并定义了3个测试指令.
基于这种思想实现其他各种运用都是条件具备的.
因为我对GE了解有限,编写只是语法正确达到效果,但是肯定有很多瑕疵和不足,你甚至能在代码段中看到Jass的残留....
此外,GE的物编结构和整体架构我现在也了解有限,只是从代码这一隅来试着做一些实践,很有可能字典树在GE中的用处都很小很局限.
目前这个字典树不能回溯,也不能插入和删除节点,某种程度上是因为Galaxy不能直接结构体,而数据表字符目录不好修改,但是大概确实是我目前水平有限所致.
(WE里面的字典树是能做到回溯和删改的,毕竟用的是伪结构体).
在此还是感谢教程区的几个帖子,为我转写这个字典树起了指导作用:
1.5.0 “指针归来”函数/结构/数组引用的语法教程
StarCraft2 地图编辑器 Galaxy教程
还感谢7键前辈告诉我怎么挂接库的依赖关系.
拙作多不足,还请多指教.
RaiKeg_Galaxy_1.0.SC2Mod
(16 KB, 下载次数: 6)
画质比较渣,不要吐槽我...
|
评分
-
查看全部评分
|