Unity肉鸽卡牌开发记录01-卡牌SO的构建和CSV文件读取
构建卡牌SO
- 使用ScriptableObject来保存卡牌的数据
- 卡牌有多种类型,一些类型的卡牌有自身独有的属性(如怪兽卡有怪兽种族)
- 构建卡牌基类SO,之后每种类型的卡牌继承他并创建各自独有的属性

- 卡牌的类型、所属阵营、品质、怪兽卡种族、怪兽职业使用枚举类型表示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| using System.Collections; using System.Collections.Generic; using UnityEngine;
public class Card : ScriptableObject { public int cardId; public int pointCost;
public string cardName;
public Sprite icon;
public CardType type;
public string ability;
public string introduce;
public Camp camp;
public Quality cardQuality; }
public enum CardType { Monster, Magic, Equipment, Weapon, Trap, Arena }
public enum Camp { General, WeaponMaster, Summoner, Necromancer, TrapArtisan, Rouge }
public enum Quality { Common, Rare, Epic, Legend }
|
读取CSV文件,自动创建卡牌SO
- 从CSV文件读取卡牌数据,自动创建或更新SO
Resources.Load<TextAsset>("")读取CSV文件
Resources.Load<Monster>("")加载已有的SO,File.Exists(cardPath)判断卡牌是否已经存在
ScriptableObject.CreateInstance<Monster>()创建SO实例
AssetDatabase.CreateAsset将内存中的SO保存为asset文件,保存后记得AssetDatabase.SaveAssets()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
| using System.Collections; using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine;
public class CsvToSO : MonoBehaviour { public CardList cardList;
private TextAsset csvData;
private void Start() { cardList.cardList.Clear(); ReadCsv(); }
void ReadCsv() { csvData = Resources.Load<TextAsset>("CardInfo"); string[] csvRow = csvData.text.Split('\n'); string[] dataPerRow; foreach (var row in csvRow) { dataPerRow = row.Split(','); if(dataPerRow[0] == "卡牌ID") { continue; } else { switch (dataPerRow[3]) { case "怪兽卡": HandleMonsterCard(dataPerRow); break; case "魔法卡": HandleMagicCard(dataPerRow); break; case "装备卡": HandleEquipmentCard(dataPerRow); break; case "武器卡": HandleWeaponCard(dataPerRow); break; case "陷阱卡": HandleTrapCard(dataPerRow); break; case "场地卡": HandleArenaCard(dataPerRow); break; default: Debug.Log("卡牌ID:" + dataPerRow[0] + "数据有误"); break; } } } Debug.Log("CSV文件处理完毕"); }
void HandleMonsterCard(string[] monsterRow) { string cardPath = Application.dataPath+"/Resources/ScriptableObj/Cards/MonsterCards/" + monsterRow[1]+".asset"; if(File.Exists(cardPath)) { Debug.Log("卡牌:" + monsterRow[2] + " 已经存在,正在更新数据"); Monster monster = Resources.Load<Monster>("ScriptableObj/Cards/MonsterCards/" + monsterRow[1]); HandleGeneralData(monsterRow, monster, CardType.Monster); monster.atk = int.Parse(monsterRow[9]); monster.hp = int.Parse(monsterRow[10]); monster.shield = int.Parse(monsterRow[11]); monsterRow[13] = monsterRow[13].Split('\r')[0]; monster.race = CardEnumConvertor.GetInstance().StringToMonsterRaceEnum(monsterRow[12], monsterRow[0]); monster.duty = CardEnumConvertor.GetInstance().StringToMonsterDutyEnum(monsterRow[13], monsterRow[0]); EditorUtility.SetDirty(monster); AssetDatabase.SaveAssetIfDirty(monster); AssetDatabase.Refresh(); Debug.Log("卡牌:" + monsterRow[2] + " 数据更新完毕"); } else { Monster monster = ScriptableObject.CreateInstance<Monster>(); HandleGeneralData(monsterRow, monster, CardType.Monster); monster.atk = int.Parse(monsterRow[9]); monster.hp = int.Parse(monsterRow[10]); monster.shield = int.Parse(monsterRow[11]); monsterRow[13] = monsterRow[13].Split('\r')[0]; monster.race = CardEnumConvertor.GetInstance().StringToMonsterRaceEnum(monsterRow[12], monsterRow[0]); monster.duty = CardEnumConvertor.GetInstance().StringToMonsterDutyEnum(monsterRow[13], monsterRow[0]); AssetDatabase.CreateAsset(monster, "Assets/Resources/ScriptableObj/Cards/MonsterCards/" + monsterRow[1] + ".asset"); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); }
Monster monsterCard = Resources.Load<Monster>("ScriptableObj/Cards/MonsterCards/" + monsterRow[1]); cardList.cardList.Add(monsterCard); Debug.Log("卡牌ID"+monsterRow[0]+",卡牌名称:" + monsterRow[2] + " 处理完毕"); }
void HandleGeneralData(string[] dataRow,Card card,CardType cardType) { card.cardId = int.Parse(dataRow[0]); card.cardName = dataRow[2]; card.type = cardType; card.pointCost = int.Parse(dataRow[4]); switch (dataRow[5]) { case "通用": card.camp = Camp.General; break; case "武器大师": card.camp = Camp.WeaponMaster; break; case "召唤师": card.camp = Camp.Summoner; break; case "死灵术士": card.camp = Camp.Necromancer; break; case "陷阱工匠": card.camp = Camp.TrapArtisan; break; case "侠盗": card.camp = Camp.Rouge; break; default: card.camp = Camp.General; break; } card.ability = dataRow[6]; card.introduce = dataRow[7]; switch (dataRow[8]) { case "普通": card.cardQuality = Quality.Common; break; case "稀有": card.cardQuality = Quality.Rare; break; case "史诗": card.cardQuality = Quality.Rare; break; case "传说": card.cardQuality = Quality.Legend; break; default: break; } }
}
|
注意:对于已经存在的卡牌SO,在修改其属性后要标记其为脏数据并保存
1 2 3 4
| EditorUtility.SetDirty(monster); AssetDatabase.SaveAssetIfDirty(monster); AssetDatabase.Refresh();
|
CardListSO:用于存储所有的卡牌,在游戏中可以随时取用
1 2 3 4 5 6 7 8 9
| using System.Collections; using System.Collections.Generic; using UnityEngine;
[CreateAssetMenu(menuName ="CardList")] public class CardList : ScriptableObject { public List<Card> cardList = new List<Card>(); }
|
MenuItem是在UnityEditor命名空间下的一个类,它允许你可以在Unity编辑器中添加自定义的菜单,同时也可以允许添加快捷键。
注意只适用于静态方法。
1 2 3 4 5
| [MenuItem("ReadCsv/ReadCsvDataToSO")] static void ReadCsvDataToSO() { ReadCsv(); }
|
TODO:
- [ ] 目前暂无卡牌图片素材,待卡牌图片素材产出后添加自动设置Card类icon字段的功能
- [ ] 优化CSVToSO脚本,使之在Editor中就可以运行