【Unity】CSVファイルを読み込んで名前を管理するデータベースを作成する

Tips

ランダムな日本人名を作成したく、姓名データをCSVにしたものはいいものの、Unityで管理できるようにデータベース化したかったためそれをする。

データベースには前回使用したScriptableObjectを利用する。

前回の記事は以下

データベース管理

管理データのCSV化

まずは姓名データを管理するCSVを用意する

→したものがこちら

データはこことかここを参考に引っ張ってきた

姓データにのみ頻出度(Frequency)というパラメータを付けている。

これは有名な苗字(「佐藤」とか「鈴木」)とかは頻出度を高くして、後々名前を自動生成させるときに制御させるために任意でつけた。

構成図

構成はこんな感じ。

今回は姓名データ自体はScriptableObject化せず、CSVからインポートさせるような形式にしてみる

構築

データベース作成

まずはデータとデータベース部分を作成する。

今回は姓名データ自体はScriptableObject化しないため、同じスクリプトファイルに管理するデータ自体も書いてしまう。

NameDataBase.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
[CreateAssetMenu(menuName = "NameDataBase")]
public class NameDataBase : ScriptableObject
{
    [SerializeField] public List<LastName> lastNameList = new List<LastName>();
    [SerializeField] public List<FirstName> firstNameList = new List<FirstName>();

    public void AddNameData(LastName _lastName)
    {
        this.lastNameList.Add(_lastName);
    }

    public void AddNameData(FirstName _firstName)
    {
        this.firstNameList.Add(_firstName);
    }
}

[System.Serializable]
public class LastName
{
    public string lastnameKanji;    // 苗字(漢字)
    public string lastnameReading;  // 読み方
    public int frequency;           // 頻出度
}

[System.Serializable]
public class FirstName
{
    public string firstnameKanji;    // 名前(漢字)
    public string firstnameReading;  // 読み方
}

データを追加する関数も書いてみた。

前回のデータベースを構築した際もこうすればよかったと反省したため。

どこかのタイミングで作り直すだろうと思いつつ、それは未来の自分にまかせる

[System.Serializable]を指定しておかないとInspector上で表示されないので、ちゃんと管理するデータクラスに付与しておく。

あとはAssetオブジェクトを作成しておくこと。

データ登録スクリプトの作成

データベースを作成したので、次はそのデータベースにデータを登録するスクリプトを用意する。

機能としては

  • 名前用、苗字用のCSVファイルを読み込む
  • CSVファイルの中身を1行ずつ処理する
  • Assetオブジェクト化させたデータベースオブジェクトに対してデータを登録する

CsvImportTool.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System;

public class CsvImportTool : MonoBehaviour
{
    [SerializeField] private NameDataBase nameDataBase;
    [SerializeField] private TextAsset lastNameCsv;
    [SerializeField] private TextAsset firstNameCsv;

    // Start is called before the first frame update
    void Start()
    {
        SetFirstNameDataBaseFromCsv();
        SetLastNameDataBaseFromCsv();
    }

    /// <summary>
    /// CSVから苗字データをデータベースに登録する関数
    /// </summary>
    public void SetFirstNameDataBaseFromCsv()
    {
        StringReader reader = new StringReader(firstNameCsv.text);

        // 処理行数を管理する変数
        int lineCount = 1;

        // CSVの中を1行ずつ処理
        while (reader.Peek() != -1) // reader.Peekが-1になるまで
        {
            // 一行ずつ読み込み
            string line = reader.ReadLine();

            // 1行目の処理(カラム名等)は処理を飛ばす
            if (lineCount == 1)
            {
                lineCount++;
                continue;
            }

            // カンマで区切って配列に入れる
            string[] lineArray = line.Split(",");

            Debug.Log(firstNameCsv.name + "の [" + lineCount.ToString() + "] 行目を処理中... [" + lineArray[0] + "]");

            // データベースに追加
            FirstName fstn = new FirstName();
            fstn.firstnameKanji = lineArray[0];
            fstn.firstnameReading = lineArray[1];
            nameDataBase.AddNameData(fstn);

            lineCount++;
        }
    }

    /// <summary>
    /// CSVから名前データをデータベースに登録する関数
    /// </summary>
    public void SetLastNameDataBaseFromCsv()
    {
        StringReader reader = new StringReader(lastNameCsv.text);

        // 処理行数を管理する変数
        int lineCount = 1;

        // CSVの中を1行ずつ処理
        while (reader.Peek() != -1) // reader.Peekが-1になるまで
        {
            // 一行ずつ読み込み
            string line = reader.ReadLine();

            // 1行目の処理(カラム名等)は処理を飛ばす
            if (lineCount == 1)
            {
                lineCount++;
                continue;
            }

            // カンマで区切って配列に入れる
            string[] lineArray = line.Split(",");

            Debug.Log(lastNameCsv.name + "の [" + lineCount.ToString() + "] 行目を処理中... [" + lineArray[0] + "]");

            // データベースに追加
            LastName lstn = new LastName();
            lstn.lastnameKanji = lineArray[0];
            lstn.lastnameReading = lineArray[1];
            lstn.frequency = Int32.Parse(lineArray[2]);
            nameDataBase.AddNameData(lstn);

            lineCount++;
        }
    }
}

以下でインポートするCSVと操作(データ追加)するデータベースAssetオブジェクトを指定する

    [SerializeField] private NameDataBase nameDataBase;
    [SerializeField] private TextAsset lastNameCsv;
    [SerializeField] private TextAsset firstNameCsv;

CSVを1行ずつ読み込むのは

while (reader.Peek() != -1) // reader.Peekが-1になるまで
        {
            // 一行ずつ読み込み
            string line = reader.ReadLine();

の部分。

reader.ReadLine()が実行されるとreader.Peekが消費され、残りの行数が0になるまで繰り返す。

あとはCSVファイルを読み込んで、区切り文字で区切ってそれぞれのパラメータをFirstNameクラスおよびLastNameクラスにセットしてデータベースに登録するだけ。

実行する際にはInspectorからCSVファイルとNameDataBaseのAssetオブジェクトを設定しておくこと。

GameObjectにアタッチ

空のGameObject(今回は「CsvImportTool」という名前)を作成して、「CsvImportTool.cs」をそのオブジェクトにアタッチする。

上記した通り、実行する際にはCSVファイルとNameDataBaseのAssetオブジェクトを設定する。

ゲームを再生するとStart()メソッドに書いてある読み込み関数が実行される。

実行結果

実行するとこんな感じ。

ScriptableObjectなので一回登録すれば恒久的に利用できる。

ので、このスクリプトを使うのは一番初めだけ(もしくは後程CSVファイルを再読み込みしたい場合)

あとがき

こういうツール系のスクリプトはStart()に書いてゲーム実行させるよりもInspectorにボタンを追加してそこで実行したほうが便利。(下図みたいに)

【TODO】Editorの作り方も後日整理する

タイトルとURLをコピーしました