设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 3040|回复: 2
打印 上一主题 下一主题

[交流讨论] CSV转Json实验日志: 设定表格转游戏数据 (新增excel转换)

[复制链接]

Lv3.寻梦者

梦石
0
星屑
1912
在线时间
1554 小时
注册时间
2013-4-13
帖子
917
跳转到指定楼层
1
发表于 2020-6-8 02:29:42 | 只看该作者 回帖奖励 |正序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
本帖最后由 沉滞的剑 于 2020-6-8 13:30 编辑

继续搞事情....

设定用表格很方便, 但是游戏中还是JSON结构清楚
写一遍设定再录入一遍数据实在是太蠢了, 所以需要搞一个脚本来辅助工作

我有很多张CSV表格, 我要把它们每一张都输出为Json格式, 并且还想支持一些简单的不定长的数据结构

例子1 - 最简单的情形

我需要一些文本描述:

id,name,note
hp,生命,"人物能够承受的伤害, 初始为12点"
belly,饱腹,"人物能承受的饥饿, 初始为15点, 饱腹不足时将由生命值承受饥饿"
exp,经验,"用来提升最大生命或者属性的资源. 每100点经验可以换取1点最大生命或1点属性点, 每次换取属性点的花费增加50."
gp,金币,"用来交易物品的资源"
attr,属性,"表示角色的不同能力的强度, 每一项最多10点"
str,力量,"人物属性, 每点力量提高1点攻击, 初始为1点"
int,智力,"人物属性, 每点智力获得额外5点战斗经验, 初始为1点"
spd,速度,"人物属性, 战斗中速度高的角色先出手, 初始为1点"
weapon,武器,"提供额外攻击的装备"
armor,防具,"提供额外防御的装备"
accessory,饰品,"提供额外效果的装备"
atk,攻击伤害,"攻击所能造成的基本伤害"
def,伤害抵抗,"能够抵消一次攻击的攻击伤害总量, 最多降低伤害到1点"

CSV要求每一列用逗号分隔, 如果文本中有都好需要用双引号将整个文本括起来
最后输出的结果是:

[
  { "id": "hp", "name": "生命", "note": "人物能够承受的伤害, 初始为12点" },
  { "id": "belly", "name": "饱腹", "note": "人物能承受的饥饿, 初始为15点, 饱腹不足时将由生命值承受饥饿" },
  {
    "id": "exp",
    "name": "经验",
    "note": "用来提升最大生命或者属性的资源. 每100点经验可以换取1点最大生命或1点属性点, 每次换取属性点的花费增加50."
  },
  { "id": "gp", "name": "金币", "note": "用来交易物品的资源" },
  { "id": "attr", "name": "属性", "note": "表示角色的不同能力的强度, 每一项最多10点" },
  { "id": "str", "name": "力量", "note": "人物属性, 每点力量提高1点攻击, 初始为1点" },
  { "id": "int", "name": "智力", "note": "人物属性, 每点智力获得额外5点战斗经验, 初始为1点" },
  { "id": "spd", "name": "速度", "note": "人物属性, 战斗中速度高的角色先出手, 初始为1点" },
  { "id": "weapon", "name": "武器", "note": "提供额外攻击的装备" },
  { "id": "armor", "name": "防具", "note": "提供额外防御的装备" },
  { "id": "accessory", "name": "饰品", "note": "提供额外效果的装备" },
  { "id": "atk", "name": "攻击伤害", "note": "攻击所能造成的基本伤害" },
  { "id": "def", "name": "伤害抵抗", "note": "能够抵消一次攻击的攻击伤害总量, 最多降低伤害到1点" }
]

例子2 - 不定长的数据

我需要定义一种'效果'函数, 它接收不定长数量的参数, 我希望能转换为参数列表并附带描述:

id,name,type,params,note
atk,伤害,always,dmg:伤害加成,攻击伤害提高$1
atkAttr,属性加成伤害,always,attr:属性类型;dmg:每点属性提供的伤害加成,每点#1提高$2点攻击伤害

最后输出的结果是:

[
  {
    "id": "atk",
    "name": "伤害",
    "type": "always",
    "params": [{ "name": "dmg", "note": "伤害加成" }],
    "note": "攻击伤害提高$1"
  },
  {
    "id": "atkAttr",
    "name": "属性加成伤害",
    "type": "always",
    "params": [
      { "name": "attr", "note": "属性类型" },
      { "name": "dmg", "note": "每点属性提供的伤害加成" }
    ],
    "note": "每点#1提高$2点攻击伤害"
  }
]

我约定xxx:yyy的结构代表名称为xxx, 描述为yyy

例子3 - 另一个不定长的数据

我需要让其他数据使用我之前定义的效果函数, 而且让它看上去是另一种语法

id,name,effects,type,value,note
shortsword,短剑,"atk(5)",dagger,10,"轻便灵活的护身武器, 新人冒险家用它来杀死野狼."
sword,长剑,"atk(8)",sword,20,"从雇佣兵到骑士团, 人人都爱用的可靠武器."
lance,骑枪,"atk(5);atkAttr(spd,3)",polearms,80,"冲锋! 骑枪之下众生平等."

转换后的结果为:

[
  {
    "id": "shortsword",
    "name": "短剑",
    "effects": [{ "id": "atk", "params": ["5"] }],
    "type": "dagger",
    "value": "10",
    "note": "轻便灵活的护身武器, 新人冒险家用它来杀死野狼."
  },
  {
    "id": "sword",
    "name": "长剑",
    "effects": [{ "id": "atk", "params": ["8"] }],
    "type": "sword",
    "value": "20",
    "note": "从雇佣兵到骑士团, 人人都爱用的可靠武器."
  },
  {
    "id": "lance",
    "name": "骑枪",
    "effects": [
      { "id": "atk", "params": ["5"] },
      { "id": "atkAttr", "params": ["spd", "3"] }
    ],
    "type": "polearms",
    "value": "80",
    "note": "冲锋! 骑枪之下众生平等."
  }
]

将多个效果和它的参数解析出来, 同时保证原数据还具有一定的可读性.

最后脚本是用NodeJS写的, 其实也可以考虑用Python, 如果用pandas一定会实现更加复杂的效果, 至少不需要手写csv的解析了


JAVASCRIPT 代码复制
  1. const fs = require("fs");
  2. const path = require("path");
  3. const _ = require("lodash");
  4.  
  5. const parseCol = (name, col) => {
  6.   const list = col.split(";").filter(Boolean);
  7.   const head = _.head(list);
  8.   if (["id", "name", "note"].includes(name)) return col;
  9.   if (/^.+:.+$/.test(head)) {
  10.     return list.map((item) => {
  11.       const pairs = item.split(":");
  12.       return {
  13.         name: pairs[0],
  14.         note: pairs[1],
  15.       };
  16.     });
  17.   } else if (/^.+[(].+[)]$/.test(head)) {
  18.     return list.map((item) => {
  19.       const [_, id, params] = item.match(/^(.+)[(](.+[,]?)+[)]$/);
  20.       return {
  21.         id,
  22.         params: params.split(","),
  23.       };
  24.     });
  25.   } else if (/^\[.+\]$/.test(col)) {
  26.     return col.split(",");
  27.   }
  28.   return col;
  29. };
  30. const parseFile = async (src, dst, filename) => {
  31.   const data = await fs.promises.readFile(path.resolve(src, filename), "utf-8");
  32.   const lines = data.split("\r\n").map((item) => {
  33.     let flag = true;
  34.     const list = [0];
  35.     const subStrings = [];
  36.     item.split("").forEach((v, i) => {
  37.       if (v === '"') return (flag = !flag);
  38.       if (v === "," && flag) {
  39.         list.push(i);
  40.         subStrings.push(item.substring(list[0], list[1]).replace(/^["](.*)["]$/, "$1"));
  41.         list.shift();
  42.         list[0] += 1;
  43.       }
  44.     });
  45.     subStrings.push(item.substring(list[0]).replace(/^["](.*)["]$/, "$1"));
  46.     return subStrings;
  47.   });
  48.   const head = lines.shift();
  49.   const obj = lines.map((line) => _.fromPairs(line.map((col, index) => [head[index], parseCol(head[index], col)])));
  50.   await fs.promises.writeFile(path.resolve(dst, filename.replace(/csv$/, "json")), JSON.stringify(obj));
  51. };
  52.  
  53. // 程序入口, 将src文件夹下的所有文件转化为json格式(不要放其他类型的文件和文件夹进去)
  54. const src = "./data/Cards/CSV";
  55. const dst = "./data/Cards/JSON";
  56. const filenames = fs.readdirSync(src, "utf-8");
  57. filenames.forEach((item) => {
  58.   parseFile(src, dst, item);
  59. });


新增用pandas写的直接将excel的所有sheets转换为JSON

PYTHON 代码复制
  1. import pandas as pd
  2. import numpy as np
  3. import json
  4. import re
  5.  
  6. excel_path = 'data/Cards/Excel/cards.xlsx'
  7. json_path = 'data/Cards/JSON/'
  8.  
  9.  
  10. def parseCol(col):
  11.     partterns = {
  12.         'func': {
  13.             'pattern': r'(.+?)[(](.*?)[)];?',
  14.             'method': lambda matches: [
  15.                 {
  16.                     'name': x[0],
  17.                     'params': [*[y for y in x[1].split(',') if y is not '']]
  18.                 }
  19.                 for x in matches
  20.             ]
  21.         },
  22.         'params': {
  23.           'pattern': r'([^;]+?)[:]([^;]+)[;]?',
  24.           'method': lambda matches: [
  25.                 {
  26.                     'name': x[0],
  27.                     'note': x[1]
  28.                 }
  29.                 for x in matches
  30.           ]
  31.         }
  32.     }
  33.     for v in partterns.values():
  34.         matches = re.findall(pattern=v['pattern'], string=str(col))
  35.         if len(matches):
  36.             return v['method'](matches)
  37.     return str(col)
  38.  
  39.  
  40. sheets = pd.read_excel(excel_path, sheet_name=None)
  41. sheet_names = list(sheets.keys())
  42.  
  43. for each in sheet_names:
  44.     sheet = sheets[each]
  45.     values = list(sheet.values.flatten())
  46.     data = pd.DataFrame(
  47.         np.array(list(map(parseCol, sheet.values.flatten())),
  48.                  dtype="object").reshape(sheet.shape),
  49.         columns=sheet.columns).to_dict(orient="record")
  50.     with open(json_path + each + '.json', mode='w', encoding='utf-8') as file:
  51.         json.dump(data, file, ensure_ascii=False)





夏普的道具店

塞露提亚-道具屋的经营妙方同人作品
发布帖:点击这里
头像被屏蔽

Lv2.观梦者 (禁止发言)

梦石
0
星屑
724
在线时间
918 小时
注册时间
2010-11-13
帖子
1023
3
发表于 2020-7-19 17:30:56 | 只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

Lv4.逐梦者

梦石
0
星屑
7326
在线时间
1444 小时
注册时间
2018-12-16
帖子
2034
2
发表于 2020-6-8 06:49:16 | 只看该作者
本版块需要密码,您必须在下面输入正确的密码才能浏览这个版块
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-11-26 05:56

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表