实际开发过程中,策划习惯使用 Excel 填写游戏数据,而程序使用的配置数据一般是 xml,json,lua 或者某种自定义的 DSL (Domain Specific Language) 等,或是 scriptable 等二进制文件,所以产生了一个把 Excel 里的数据转换成程序所需要的 "导表" 的过程.
一般团队的导表工具都是程序写的,有好的方面,也有坏的方面.好的方面是: 程序会对比 MD5 码来确定文件一致.坏的方面是: 要规定文件路径,只能一次性转换所有表格,或者选择所需转换表格时难用的 UI, 表格 sheet 名和表的某一行必须有特殊规定等.最大的问题还是这个工具对策划并不开源,加上导表工具里还有上传 SVN, 重启服务器等一系列自动化操作,出了错误之后无法确定是配置数据问题,还是工具问题,网络问题,在这条管线里面,就有了巨大的甩锅空间.
所以策划要牢牢把握住这口锅,出了错就是你配置的错,谁让你离开了 Excel 连游戏都不会做了呢? 下面以 json 格式举例,讲几种策划也能学会的方法,制作自己的导表工具.
题外话,非常不推荐直接把 Excel 导入进数据库的操作.
方法一: 手动转换
最简单的就是复制粘贴手动存成 json, 对,就这样干,因为程序要的就是个 json 文件而已.沙塔斯城里的商人说过一句话:
"你要战争,我就给你战争,水果贩."
我们先分析下 json 格式一般是什么样的,以下面这段为例:
可以看出,整个文件是用大括号 {} 包裹起来,左边引号里的是 key, 右边是对应的 value. Value 有多种类型: 是个数字的 / 用引号圈起来的 / 用大括号圈起来的 / 和用中括号圈起来的,那么我们只要弄成这样就好了.
下面看 excel 表格里面的格式一般是这样的:
第一行是字段名,下面是字段的值,一般用 id 作为数据库里面的 key, 或者还有自动生成的 uid, 增加一行用作标记改字段的类型等,大差不差的内容.我们需要的就是把每一行都通过 "字段: 值,字段: 值..." 的形式连接起来,然后用个大括号来包裹即可.
我们后面加一列,通过 Excel 的函数,来获取我们需要的数据.给策划新人们一个建议,就是函数要一步一步地写,哪怕一共有十几步,每一步的结果都放在一列里,确认结果正确后,再拼接到一起,写一个超长的函数 (不能超过 255 个字符), 然后删掉中间的步骤,云淡风轻地对旁边的人说:"不就是这样简单吗?"
第一步:
=INDEX($A$1:$F$1,COLUMN(A2))
index 函数用来获得字段名,第一个参数 $A$1:$F$1 是第一行需要的字段范围,注意加上 $ 符号,快捷键是 F4...(自己搜索吧,有一种教人 ' 这是冰箱 ' 的感觉), 第二个参数是当前值所在的列号,如果前面还有空行的话,这里要减去相应的数量.
横着一拖,竖着一拖,看到了需要的内容是我们要的 key.
接着连接冒号和每一行的值:
=INDEX($A$1:$F$1,COLUMN(A2))&":"&A2
然后使用 textJoin 函数,连接在一起,外面接上大括号就好了.
="{"&TEXTJOIN(",",TRUE,G2:L2)&"}"
有人问了,所需要的 json 的 key 有引号的啊,要怎么办?
最简单的就是字段名字就给他加上引号!
到这里主体部分就完成了,每一条 {} 大括号里面的,都是个 json 的对象.对象之间用 [] 包裹起来,就是一个 json 的列表,或者还有 {} 包裹组成 kv 对,那么就只需要在把拼接的内容再次按照要求拼接就好了.
有人可能会问了,最重要的云淡风轻,怎么还没讲? 这么多辅助列,明明是手忙脚乱啊? 怎么能写到一个函数里面啊?
别急,这里我们要用到数组公式.直接上公式:
{="{"&TEXTJOIN(",",TRUE,INDEX($A$1:$F$1,COLUMN(A2:F2))&":"&A2:F2)&"}"}
只要把值从一个格子 A2, 变成一个范围 A2:F2, 然后按 CTRL+SHITF+ENTER 输入数组公式就好了.(数组公式最外面的大括号不是打字打上去的...)
至此,终于可以云淡风轻了,因为一般程序猿也不太会用 Excel, 这样就显得你很专业了.
方法二: 自定义函数加载项
上面的例子中,有的字段的值是数组,用 [] 中括号引起来,例如
"keywords":["小猪","小肚","小鸡"]
或者自定义的类似 lambda 表达式的东西
scripts:(Count(Unit))=100&Count(Wonder)=3IsDead(Bob)
这个时候为了策划填表方便,可能每一列都有特殊的拼接方法,我们在第二行里面写上值的类型,示例如下:
这种会有很多特殊的,定制的内容,例如看到 lambda 的时候,赋值给一个临时变量名,例如
lambda1=(Count(Unit))>=100&Count(Wonder)>=3)||IsDead(Bob)
array 字段为了策划填写方便,用逗号分割起来,生成的时候还是要分别加上引号,并用中括号括起来
"keyword":["小猪","小肚","小鸡"]
面对这些定制化的需求,直接用 Excel 里的函数,就捉襟见肘了.那么我们来自己写一个,高度定制化的函数。
打开 Visual Basic 的 IDE,如果你的 Excel 不显示开发工具选项卡,则需要在自定义功能区里勾选一下。
插入一个模块,写入下列代码:
Function textToJson(ByVal s As Variant) Dim myKey,myValue Dim valueType Dim output '将单元格范围作为选中范围 Dim mr As Range Set mr = s '读取第一行的key,和当前的value组成一对 For Each i In mr If Not IsEmpty(i) And i <> 0 Then '通过第二行的类型来处理对应的值 valueType = Cells(2, i.Column) myKey = Cells(1, i.Column) myValue = i.value Select Case valueType 'lambda把key特殊处理,加一个用行号作为序列号的变量 Case "lambda" myKey = "lambda" & i.Row - 2 output = output & myKey & "=" & myValue & "," 'array把值特殊处理,将逗号分隔的字符串放在一个数组里 Case "array" temp = "" tempString = Split(i.value, ",") For Each k In tempString temp = temp & Chr(34) & k & Chr(34) & "," Next k temp = Left(temp, Len(temp) - 1) temp = "[" & temp & "]" myValue = temp output = output & myKey & ":" & myValue & "," '情况不做处理 Case Else output = output & myKey & ":" & myValue & "," End Select End If Next i '最后拼接一下 If IsError(output) Or Len(output) <= 1 Then textToJson = "" Else output = Left(output, Len(output) - 1) textToJson = "{" & output & "}" End If End Function
这样我们定义了 textToJson()这个函数,在最后一列里面输入 = textToJson (A3:F3) 即可转换。
如果其他表格也想使用该函数,但是不想转换成 xlsm 这带宏的格式,怎么办?
我们可以把这个文件另存为 xlam,作为加载宏,给其他表格使用。
其他表格使用时,通过开发工具》Excel 加载项》浏览 找到该文件,即可使用 textToJson 这个自定义函数。
方法三:VBA
上面既然已经用了自定义函数,还要另存为等手动操作,那么不如使用 VBA 直接导出。写法基本一样,只不过创建了一个 json 文件作为 object 来承载导出的内容。注意,如果报出找不到对象的错误的话,那么可以去人民公园试试。
Sub toJson() Dim i, j, k As Integer Dim myString, output As String Dim myRange As Range Dim myArr() Dim myTitle() Dim WriteStream As Object Set MyFile = CreateObject("Scripting.FileSystemObject").OpenTextFile("D:\testjson.json", 8, True) myString = "" output = "" i = 0 j = 0 k = 0 Set myRange = Selection myArr = myRange ReDim myTitle(20) For k = 0 To myRange.Columns.Count - 1 myTitle(k) = myArr(1, k + 1) Next k For i = 2 To myRange.Rows.Count output = output & "{" For j = 1 To myRange.Columns.Count If myTitle(j - 1) = "truth" Then myString = Trim(myArr(i, j)) output = output & Chr(34) & myTitle(j - 1) & Chr(34) & ":" & LCase(myString) & "," ElseIf myTitle(j - 1) = "tag" Or myTitle(j - 1) = "falseWord" Then myString = Trim(myArr(i, j)) output = output & Chr(34) & myTitle(j - 1) & Chr(34) & ":[" & mySubString(myString) & "]," ElseIf myTitle(j - 1) = "difficulty" Then myString = Trim(myArr(i, j)) output = output & Chr(34) & myTitle(j - 1) & Chr(34) & ":" & myString & "," Else myString = Trim(myArr(i, j)) output = output & Chr(34) & myTitle(j - 1) & Chr(34) & ":" & Chr(34) & myString & Chr(34) & "," End If Next j output = Mid(output, 1, Len(output) - 1) output = output & "}," & Chr(10) Next i output = Mid(output, 1, Len(output) - 2) ' Set WriteStream = CreateObject("ADODB.Stream") ' ' With WriteString' .Type = 2' .Charset = "UTF-8"' ' End With MyFile.WriteLine (output) MyFile.Close Set MyFile = Nothing MsgBox "成功!!" 'UserForm1.TextBox1.Text = output 'UserForm1.Show End Sub
以上代码是我们做过的一个答题游戏的例子,超过几万条有趣的问题。配置表可以稍微露一下:
方法四:其他
大家可能会问了,这一个一个表格的导出,太麻烦了,能不能一起导出多张?很多公司用 VBA 写过导出多张表格的工具,我也写过,但因为 VBA 先天的弱势,速度极慢,还容易卡死。
这里推荐用 python 去写,速度快 100 倍。可以用 openpyxl 库,至于如何写,可以参考上一篇文章:世界杯到了,写个爬虫获取球员数据吧
因为很简单,在此不再赘述了,可以作为初学 python 的某种练习。还可以通过 pandas 模块把 excel 读成字典对象,然后直接存进 mySQL 或者 mongodb,根本不需要导表这个中间过程了。
本文来自微信公众号:千猴马的游戏设计之道 (ID:baima21th),作者:千两
本文由LinkNemo爬虫[Echo]采集自[https://www.ithome.com/0/657/427.htm]