概要
CSVファイルからスクリプト(csファイル)に記載されているenum(列挙型)を再構成する方法を考えました。
今回は「EditorWindow」から編集できるようにしました。
CSVファイルの読み込みについては下の記事を参考にしてください。
kiironomidori.hatenablog.com
必要なクラス
EnumRebuilder
- 今回の核となるクラスその1
- 次に紹介するクラスによってEditorWindowに表示します。
using System.Collections.Generic; using UnityEngine; using UnityEditor; using System; using System.IO; using System.Text; [Serializable] public class EnumRebuilder { [SerializeField] public bool key = false; [SerializeField] public string label; [SerializeField] public TextAsset csvFile; [SerializeField] public TextAsset scriptFile; [SerializeField] public int enumNum; [SerializeField] public int nameColumn = 0; [SerializeField] public int startCsvLine = 1; //コンストラクタ public EnumRebuilder(int i) { label = $"Element{i}"; } //enumを更新する public void RebuildEnum(string enumName) { //ファイルを読み込む List<string> scriptLines = FileReader.ReadTextFile(scriptFile); //リストから目的のenumの位置を取得 int enumPos = scriptLines.ContainFirstIndex(enumName); if (enumPos == -1) { Debug.LogError($"{enumName}が見つかりません"); return; } //続いて「{」と「}」の位置を取得 int startWriteLine = scriptLines.ContainFirstIndex("{", enumPos);//「{」の位置 int endWriteLine = scriptLines.ContainFirstIndex("}", enumPos);//「}」の位置 //enumの中身を空にする if (endWriteLine - (startWriteLine + 1) > 0) { scriptLines.RemoveRange(startWriteLine + 1, endWriteLine - (startWriteLine + 1)); } //CSVファイルを読み取る List<string[]> csvLines = FileReader.ReadCSVFile(csvFile); for (int j = 0; j < csvLines.Count - startCsvLine; j++) { scriptLines.Insert(startWriteLine + 1 + j, $"\t{csvLines[j + startCsvLine][nameColumn]} = {j},"); } //ファイルを書き込む File.WriteAllLines(AssetDatabase.GetAssetPath(scriptFile), scriptLines, Encoding.UTF8); //スクリプトのリフレッシュ EditorApplication.ExecuteMenuItem("Assets/Refresh"); } }
RebuildEnumWindow
- 今回の核となるクラスその2
- EditorWindowを作成するクラスです。
- 複数のenumを編集できるようにするために「EnumRebuilder」をリストで表示します。
using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.Linq; public class RebuildEnumWindow : EditorWindow { [SerializeField] int arraySize; [SerializeField] private List<EnumRebuilder> list = new List<EnumRebuilder>(); [MenuItem("エディタ拡張/RebuildEnumWindow")] public static void Open() { var window = GetWindow<RebuildEnumWindow>("RebuildEnumWindow"); window.Show(); } void ResetArraySize()//配列の大きさを変更 { int preArraySize = list.Count; if (preArraySize != arraySize)//現在の配列の大きさ≠入力した配列の大きさの時 { if (arraySize > preArraySize)//配列を大きくする { for (int i = preArraySize; i < arraySize; i++) { list.Add(new EnumRebuilder(i)); } } else//小さくする { for (int i = arraySize; i < preArraySize; i++) { list.RemoveAt(arraySize); } } } } void DrawArrayElement(int i)//配列の要素を描画 { //畳み込み表示をするかどうか list[i].key = EditorGUILayout.Foldout(list[i].key, list[i].label); if (list[i].key) { list[i].label = EditorGUILayout.TextField("ラベル", list[i].label); list[i].csvFile = (TextAsset)EditorGUILayout.ObjectField ("CSVファイル", list[i].csvFile, typeof(TextAsset), false); list[i].scriptFile = (TextAsset)EditorGUILayout.ObjectField ("スクリプトファイル", list[i].scriptFile, typeof(TextAsset), false); //スクリプトファイルが存在するなら描画 if (list[i].scriptFile != null) { string[] enums = FileReader.ReadTextFile(list[i].scriptFile).Where(s => s.Contains(" enum ")).ToArray(); if (enums?.Length > 0) { //scriptFIle内のすべてのenumを取得 list[i].enumNum = EditorGUILayout.Popup("設定するenumの名称", list[i].enumNum, enums); //読み取りについて list[i].startCsvLine = EditorGUILayout.IntField("読み取り開始行番号", list[i].startCsvLine); list[i].nameColumn = EditorGUILayout.IntField("enumに追加する要素列番号", list[i].nameColumn); //元のInspector部分の下にボタンを表示 if (GUILayout.Button("Enumの再設計")) { list[i].RebuildEnum(enums[list[i].enumNum]); } } } } } private void OnGUI() { var serialObj = new SerializedObject(this); serialObj.Update(); //配列のサイズの設定 arraySize = EditorGUILayout.IntField("サイズ", arraySize); if (GUILayout.Button("サイズの更新")) { ResetArraySize(); serialObj.ApplyModifiedProperties(); return; } //配列の要素を描画する for (int i = 0; i < list.Count; i++) { DrawArrayElement(i); } serialObj.ApplyModifiedProperties(); } }
FileReader & ListStringExtensions
- 先ほど紹介した2クラスの補助的なクラス
- CSVファイルの読み込みなどに必要な機能をまとめたもの
using System.Collections.Generic; using UnityEngine; using System.IO; using System.Linq; using UnityEditor; public static class ListStringExtensions//List<string>の拡張メソッド { //List<string>から指定した文字列を含む先頭の要素番号を取得 public static int ContainFirstIndex(this List<string> list, string keyword, int startIndex = 0) { for (int i = startIndex; i < list.Count; i++) { if (list[i].Contains(keyword)) { return i; } } return -1; } } public static class FileReader { //CSVファイルを読み取る public static List<string[]> ReadCSVFile(TextAsset csvFile) { //1行ごとに配列としてCSV読み取り、それをリストに変換する List<string> list = File.ReadAllLines(AssetDatabase.GetAssetPath(csvFile)).ToList(); //1行ごとの文字列を更に、カンマで区切る List<string[]> lists = new List<string[]>(); for (int i = 0; i < list.Count; i++) { lists.Add(list[i].Split(',')); } return lists; } //テキストファイルを読み取る public static List<string> ReadTextFile(TextAsset textAsset) { return File.ReadAllLines(AssetDatabase.GetAssetPath(textAsset)).ToList(); } }
使用例
①. Excelで次のファイルを用意して、ファイル名「dic.csv」としてCSV形式で保存する(形式はCSF UTF-8(コンマ区切り))
行名\列名 | A | B |
---|---|---|
0 | 日本語名 | 英語 |
1 | りんご | apple |
2 | みかん | orange |
3 | 犬 | dog |
4 | 赤 | red |
ちなみに、このCSVファイルをメモ帳で開くと以下のようになっています。
日本語名,英語 りんご,apple みかん,orange 犬,dog 赤,red
②. 次の「Sample.cs」を作成する。
public enum Jan { } public enum Eng { }
③. エディタ上で「エディタ拡張」⇒「RebuidEnumWindow」の順に選択してEditorWindowを表示する。
④. 先ほど作成したウィンドウに対して「サイズ」に2を入力して、「サイズの更新」ボタンを押す。
⑤. 更に、次のような設定(ラベルは見やすくするためのものなので設定は自由で可)をして、それぞれの「Enumの再設計」ボタンを押す。
⑥. 「Sample.cs」を開くと以下のように書き換えられていることが確認できる。
public enum Jan { りんご = 0, みかん = 1, 犬 = 2, 赤 = 3, } public enum Eng { apple = 0, orange = 1, dog = 2, red = 3, }