UnityでCSVファイルを読み込む方法の備忘録🐼
基本のやり方
CSVファイルの準備
グーグルのスプレッドシートでセルに分けて書いたものを.csv形式でダウンロードしました
このtest.csvをダブルクリックで開くとNumbersってアプリで開かれてこんな感じで見れる。
Unityで読み込む
この.csvファイルを、UnityのAssets>Resourcesに入れます。Resourcesフォルダがない場合は作って入れます。
新しいC#スクリプトを作り、以下を記入します。
using System.IO; //付け足す public class CSVReader : MonoBehaviour { private TextAsset _csvFile; //CSVファイル private List<string[]> _csvData = new List<string[]>(); //CSVファイルの中身を入れるリスト void Start() { _csvFile = Resources.Load("test") as TextAsset; //Resourceにある指定のパスのCSVファイルを格納 StringReader reader = new StringReader(_csvFile.text); //TextAssetをStringReaderに変換 while(reader.Peek() != -1){ string line = reader.ReadLine(); //1行ずつ読む _csvData.Add(line.Split(',')); //読みこんだDataをリストにAddする } for(int i = 0; i < _csvData.Count; i++){ Debug.Log("名前::::" + _csvData[i][0] + ", HP::::" + _csvData[i][1]); } } }
こんな感じになります。
CSVファイル別の書き方
ちなみに、セルに分けて書かずに1つのセルにカンマで区切って書いた場合も同じようにできました。
違うところは、1つのセルにカンマで区切っていくつか要素をかくと、
デバッグログで表示した時になぜか " " で囲まれました。こっからここまで1つのセルの要素だよってことかな?
デバッグログに表示する要素を1つ最後のやつを消したら終わりの " が消えたのでそうっぽい。
基本のやり方解説
テキストアセット
private TextAsset _csvFile; //CSVファイル
TextAssetはUnityにインポートされたテキストファイルのための形式で、.csvや.html、.txtなどのファイルをUnityに入れた時にこのTextAssetに変換されるようです。
細かいことはこちらのリファレンスを↓
docs.unity3d.com
ーー
リソースのファイルを読み込む
_csvFile = Resources.Load("test") as TextAsset;
これはAssets>Resourceにあるファイルを読み込みます。
引数にはPathを渡すので、Resource下にフォルダを作って.csvファイルを入れた場合、
例えば Resource>CSV>test.csvにある時は以下のように書きます。.csvという拡張子は書かなくてオッケーです。
_csvFile = Resources.Load("CSV/test2") as TextAsset;
ーー
String Reader
StringReader reader = new StringReader(_csvFile.text);
StringReaderはSystem.IOを書くことで使えます。
TextAssetのままだと、カンマや改行を含む文字列が全て連結されたままなので、ここでStringReaderに変換しています。
while(reader.Peek() != -1){ string line = reader.ReadLine(); _csvData.Add(line.Split(',')); }
StringReaderの.Peek()は次に読み込める文字がなくなると-1になります。
.Peekが-1になるまで .ReadLineで1行ずつ読み込んでいます。
line.Split(",")でカンマで区切ってListにAddすることができます。
1つのセルの中で改行したい
キャラのステータスなどを登録する分には上記のでいいんですが、例えばセリフをCSVで読み込みたいときなどに、一つのセリフだけど改行入れたい。みたいなことがあると思います。
わたし、めーぷるっていうの! パンダが大好きなんだよ!えへへ これからもよろしくね!
みたいに、一つのセリフとして出したいけど、改行したい!みたいな。
それをやりたくて、セルの中で改行してみたり、改行マーク?の「\n」を入れてみましたが、改行する前の文字列しか取ってくれなかったり、「\n」は文字列として捉えられちゃってダメでした。
だけど改行分セルを分けてしまうのも使いにくいので、以下のようにしました。
using System.IO; using UnityEngine.UI; public class CSVReader : MonoBehaviour { public Text _text; //結果を表示するテキスト private Character _chara = new Character(); private TextAsset _csvFile; private List<string[]> _csvData = new List<string[]>(); //最終的なデータを入れるリストを付け足す private List<string> _replacedData = new List<string>(); void Start() { _csvFile = Resources.Load("CSV/test2") as TextAsset; StringReader reader = new StringReader(_csvFile.text); Debug.Log(_csvFile.text); while(reader.Peek() != -1){ string line = reader.ReadLine(); _csvData.Add(line.Split(',')); } //////ここから先が付け足した部分/////// for(int i = 0; i < _csvData.Count; i++) { string arr = _csvData[i][0].Replace("<>", "\n"); _replacedData.Add(arr); } _text.text = _replacedData[0]; }
さっきと違う部分に注目です。
for(int i = 0; i < _csvData.Count; i++) { string arr = _csvData[i][0].Replace("<>", "\n"); _replacedData.Add(arr); } _text.text = _replacedData[0];
最初に読み込んだCSVのデータの文字列から「<>」の部分を .Replaceを使って「\n」に変換しています。CSVファイルの方は、改行したい部分に<>を入れています。
別に「<>」じゃなくてもいいのですが、思わぬところで改行されてしまわないように、会話のなかでてこなさそうな文字列をチョイスしました。
CSVで「\n」を入れていても改行コードとして読み込んでくれないですが、stringでは改行コードとして扱ってくれるため、一度読み込んだCSVデータから特定の文字列(ここでは<>)を「\n」に変換してstringに格納することで表示した時に改行されるようにしています。
場面やキャラごとに整理したい
改行できるようになったら次はキャラごととか、同じキャラでも場面ごととかでセリフを読み取れるようにしたくなったりします。
以下のように、一つのCSVからパンダさんのセリフとねこちゃんのセリフを取って切り替えられるようにしました。
CSVファイルは以下のようにしています。
1の列横向きにパンダのセリフ、2の列横向きにねこちゃんのセリフを書いています。
コードは以下の通りです。
using System.IO; public class CSVReader : MonoBehaviour { private TextAsset _csvFile; private List<string[]> _csvData = new List<string[]>(); private List<string> _replacedData = new List<string>(); //最終的なデータを入れる配列をさらに作る private List<string[]> _lineData = new List<string[]>(); void Start() { _csvFile = Resources.Load("CSV/test2") as TextAsset; StringReader reader = new StringReader(_csvFile.text); Debug.Log(_csvFile.text); while(reader.Peek() != -1){ string line = reader.ReadLine(); _csvData.Add(line.Split(',')); } /////ここから先が書き換えた部分///// for (int y = 0; y < _csvData.Count; y++) { for (int x = 0; x < _csvData[y].Length; x++) { //x軸一列分の<>を\nに変換して新しいリストにAdd string arr = _csvData[y][x].Replace("<>", "\n"); _replacedData.Add(arr); } //横一列分の数のstring配列を作る string[] data = new string[_replacedData.Count]; //横一列分をストリング配列に入れて for (int i = 0; i < _replacedData.Count; i++) { data[i] = _replacedData[i]; } //それを最終的なデータリストに入れている _lineData.Add(data); //一時的に使用する_replacedDataのリストを空にする _replacedDatas.Clear(); } } public string[] GetLines(int charaNum) { return _lineData[charaNum]; } }
書き換えた部分に注目です。
for (int y = 0; y < _csvData.Count; y++) { for (int x = 0; x < _csvData[y].Length; x++) { //x軸一列分の<>を\nに変換して新しいリストにAdd string arr = _csvData[y][x].Replace("<>", "\n"); _replacedData.Add(arr); } //横一列分の数のstring配列を作る string[] data = new string[_replacedData.Count]; //横一列分をストリング配列に入れて for (int i = 0; i < _replacedData.Count; i++) { data[i] = _replacedData[i]; } //それを最終的なデータリストに入れている _lineData.Add(data); //一時的に使用する_replacedDataのリストをからにする _replacedDatas.Clear(); }
まず、for文の中の変数宣言が「i」ではなく「y」と「x」になっています。
これはわかりやすくするためなのですが、CSVの読み取ったList
_data[縦軸][横軸]
になっていたためわかりやすくするためにyとxにしました。
その時のy軸に対してx方向にあるセルを改行付きに変換して一旦リストに入れて
for (int x = 0; x < _csvData[y].Length; x++) { //x軸一列分の<>を\nに変換して新しいリストにAdd string arr = _csvData[y][x].Replace("<>", "\n"); _replacedData.Add(arr); }
そのx軸のセルの数のstring配列を作り、変換した結果が入れてあるリストをそのまま配列にぶち込みます。
//横一列分の数のstring配列を作る string[] data = new string[_replacedData.Count]; //横一列分をストリング配列に入れて for (int i = 0; i < _replacedData.Count; i++) { data[i] = _replacedData[i]; }
そのstring配列を最終的なデータリスト List
//それを最終的なデータリストに入れている
_lineData.Add(data);
一時的に変換したものを入れていた_replacedDataを空にして
次にy軸が1進んだ時のx軸セルだけを入れれるようにします。
//一時的に使用する_replacedDataのリストをからにする
_replacedDatas.Clear();
こうすることで、最終的な_lineDataには、
_lineData[0]にはy軸0の横一列(x軸)のstring配列データが入っていることになります。
つまり、縦軸でキャラやシーンを別にして横軸にそのキャラやシーンで使うセリフを入れておけば、キャラ番号(縦軸)を指定することでそのキャラのセリフを取得することができます。
外部からキャラ番号(縦軸番号)を受け取ってその横一列分のstringデータを返します。
public string[] GetLines(int charaNum) { return _lineData[charaNum]; }
セリフを表示する側はキャラの番号を渡して一度string配列に入れ、それを1ずつ進めることでボタンを押すたびにそのボタンに割り当てられたキャラのセリフが進むという形にしています。
using UnityEngine.UI; public class LineChanger : MonoBehaviour { [SerializeField] private CSVReader _csvReader; [SerializeField] private Text[] _lineTextField; private int[] _lineNum = new int[2]; public void LineChange(int charaNum) { string[] strings = _csvReader.GetLines(charaNum); if(_lineNum[charaNum] >= strings.Length) { _lineNum[charaNum] = 0; } _lineTextField[charaNum].text = strings[_lineNum[charaNum]]; _lineNum[charaNum]++; } }
これで1つのCSVファイルからキャラ別にセリフを切り替えることができました!
以上です。
ゲームでキャラのセリフ進めてく仕組み的なのを作りたくてやったんですが
他にもっと良いやり方あったら誰か教えてください!