見出し画像

UnityのResources.Load②|テキストを読み込み、配列・List・二次元配列に変換する方法

前回の記事で、Resources.Load を使って画像や音源、プレハブなどを読み込む方法を説明しました。

Unityの Resources.Load はこれだけでなく、テキストファイルも読み込むことができます。

テキストファイルを読み込めるようになると、ゲーム内で使うデータをスクリプトに直接書かず、外部のテキストファイルとして管理できるようになります。

例えば、次のようなデータを扱うときに便利です。

  • クイズの問題データ

  • タイピングゲームの単語リスト

  • 敵キャラクターの名前やHP

  • ステージごとの設定

  • 会話文

  • アイテム名や説明文

今回は、Resources.Load を使ってテキストファイルを読み込み、配列・List・二次元配列として扱う方法を紹介します。



テキストファイルをResourcesフォルダに入れる

Resources.Load で読み込むファイルは、Resources フォルダの中に入れておきます。

例えば、次のように配置します。

Assets
 └ Resources
    └ words.txt

このとき、スクリプトから読み込むときは、拡張子 .txt は書きません。

Resources.Load<TextAsset>("words");

words.txt というファイルを読み込む場合でも、指定する名前は "words" です。


TextAssetとして読み込む

テキストファイルを読み込むときは、TextAsset を使います。

TextAsset textData = Resources.Load<TextAsset>("words");

読み込んだテキストの中身は、.text で取得できます。

Debug.Log(textData.text);

例えば、words.txt の中身が次のようになっているとします。

りんご
みかん
バナナ
ぶどう

この場合、textData.text には、テキストファイル全体の文字列が入ります。


1行ずつ分けて配列にする

テキストファイルの中身を1行ずつ分けたい場合は、Split() を使います。

using UnityEngine;

public class WordLoader : MonoBehaviour
{
    void Start()
    {
        TextAsset textData = Resources.Load<TextAsset>("words");

        string[] wordArray = textData.text.Split('\n');

        foreach (string word in wordArray)
        {
            Debug.Log(word);
        }
    }
}

Split('\n') は、改行ごとに文字を分ける処理です。

次のようなテキストを、

りんご
みかん
バナナ
ぶどう

次のような配列として扱えるようになります。

wordArray[0] = りんご
wordArray[1] = みかん
wordArray[2] = バナナ
wordArray[3] = ぶどう

単語リストや名前リストのように、1行に1つのデータを入れておく場合は、この方法が使いやすいです。


Trimで余計な改行や空白を取り除く

テキストファイルを読み込むときに注意したいのが、改行コードです。

Windowsで作ったテキストファイルでは、行の最後に見えない文字が残ることがあります。

見た目は、

りんご

でも、実際には、

りんご\r

のような文字が残っている場合があります。

このままだと、文字を比較したときにうまく一致しないことがあります。

そこで、Trim() を使います。

using UnityEngine;

public class WordLoader : MonoBehaviour
{
    void Start()
    {
        TextAsset textData = Resources.Load<TextAsset>("words");

        string[] wordArray = textData.text.Split('\n');

        foreach (string word in wordArray)
        {
            string cleanWord = word.Trim();

            Debug.Log(cleanWord);
        }
    }
}

Trim() を使うと、文字列の前後にある余計な空白や改行を取り除くことができます。
テキストデータを読み込むときは、基本的に Trim() を使っておくと安心です。


空行を除外して配列にする

テキストファイルの最後に空行があると、空のデータまで配列に入ってしまうことがあります。

そのような場合は、空行を除外して読み込むと安全です。

using System.Collections.Generic;
using UnityEngine;

public class WordLoader : MonoBehaviour
{
    void Start()
    {
        TextAsset textData = Resources.Load<TextAsset>("words");

        string[] lines = textData.text.Split('\n');

        List<string> wordList = new List<string>();

        foreach (string line in lines)
        {
            string word = line.Trim();

            if (word != "")
            {
                wordList.Add(word);
            }
        }

        string[] wordArray = wordList.ToArray();

        foreach (string word in wordArray)
        {
            Debug.Log(word);
        }
    }
}

一度 List に入れてから、最後に ToArray() で配列に変換しています。


Listとして読み込む

配列ではなく、最初から List として扱いたい場合もあります。

List は、あとからデータを追加したり削除したりしやすいのが特徴です。

using System.Collections.Generic;
using UnityEngine;

public class WordListLoader : MonoBehaviour
{
    public List<string> wordList = new List<string>();

    void Start()
    {
        TextAsset textData = Resources.Load<TextAsset>("words");

        string[] lines = textData.text.Split('\n');

        foreach (string line in lines)
        {
            string word = line.Trim();

            if (word != "")
            {
                wordList.Add(word);
            }
        }

        foreach (string word in wordList)
        {
            Debug.Log(word);
        }
    }
}

List を使う場合は、スクリプトの上に次の1行が必要です。

using System.Collections.Generic;

配列よりも柔軟に扱いたい場合は、List にしておくと便利です。


カンマ区切りのデータを読み込む

次は、1行の中に複数のデータが入っている場合です。

例えば、敵キャラクターのデータを次のようなテキストで用意します。

スライム,10,3
ゴブリン,20,5
ドラゴン,100,20

これは、

名前,HP,攻撃力

という意味のデータです。

この場合は、まず1行ずつ分けてから、さらにカンマで分けます。

using UnityEngine;

public class EnemyDataLoader : MonoBehaviour
{
    void Start()
    {
        TextAsset textData = Resources.Load<TextAsset>("enemyData");

        string[] lines = textData.text.Split('\n');

        foreach (string line in lines)
        {
            string cleanLine = line.Trim();

            if (cleanLine == "")
            {
                continue;
            }

            string[] data = cleanLine.Split(',');

            string enemyName = data[0];
            int hp = int.Parse(data[1]);
            int attack = int.Parse(data[2]);

            Debug.Log(enemyName + " / HP:" + hp + " / 攻撃力:" + attack);
        }
    }
}

Split(',') を使うことで、カンマごとにデータを分けることができます。

スライム,10,3

であれば、

data[0] = スライム
data[1] = 10
data[2] = 3

のように取り出せます。

数値として使いたい場合は、int.Parse() を使って文字列から整数に変換します。

int hp = int.Parse(data[1]);

二次元配列として読み込む

次に、テキストデータを二次元配列として読み込む方法です。

二次元配列とは、行と列を持つ表のようなデータです。

今回は、首都当てクイズのデータを例にします。

Resources フォルダの中に、capitalQuiz.txt を作ります。

Assets
 └ Resources
    └ capitalQuiz.txt

中身は次のようにします。

国,首都,ダミー1,ダミー2,ダミー3
日本,東京,大阪,京都,横浜
アメリカ,ワシントンD.C.,ニューヨーク,ロサンゼルス,シカゴ
フランス,パリ,リヨン,マルセイユ,ニース
イギリス,ロンドン,マンチェスター,リバプール,オックスフォード
イタリア,ローマ,ミラノ,ベネチア,フィレンツェ
ドイツ,ベルリン,ミュンヘン,ハンブルク,フランクフルト
カナダ,オタワ,トロント,バンクーバー,モントリオール
オーストラリア,キャンベラ,シドニー,メルボルン,ブリスベン
ブラジル,ブラジリア,リオデジャネイロ,サンパウロ,サルバドール
エジプト,カイロ,アレクサンドリア,ギザ,ルクソール

このデータは、1行が1件分のデータになっています。

国,首都,ダミー1,ダミー2,ダミー3

という形で、横方向に複数の情報が並んでいます。

このような表形式のデータは、二次元配列にすると扱いやすくなります。


見出し行も含めて二次元配列にする

まずは、見出し行も含めて二次元配列にする方法です。

using System.Collections.Generic;
using UnityEngine;

public class CapitalDataLoader : MonoBehaviour
{
    string[,] dataArray;

    void Start()
    {
        TextAsset textData = Resources.Load<TextAsset>("capitalQuiz");

        string[] lines = textData.text.Split('\n');

        List<string> cleanLines = new List<string>();

        foreach (string line in lines)
        {
            string cleanLine = line.Trim();

            if (cleanLine != "")
            {
                cleanLines.Add(cleanLine);
            }
        }

        int rowCount = cleanLines.Count;
        int columnCount = cleanLines[0].Split(',').Length;

        dataArray = new string[rowCount, columnCount];

        for (int row = 0; row < rowCount; row++)
        {
            string[] values = cleanLines[row].Split(',');

            for (int column = 0; column < columnCount; column++)
            {
                dataArray[row, column] = values[column];
            }
        }

        Debug.Log(dataArray[1, 0]);
        Debug.Log(dataArray[1, 1]);
    }
}

二次元配列は、次のように取り出します。

dataArray[行, 列]

今回の場合、配列の番号は次のようになります。

dataArray[0, 0] = 国
dataArray[0, 1] = 首都
dataArray[0, 2] = ダミー1
dataArray[0, 3] = ダミー2
dataArray[0, 4] = ダミー3

dataArray[1, 0] = 日本
dataArray[1, 1] = 東京
dataArray[1, 2] = 大阪
dataArray[1, 3] = 京都
dataArray[1, 4] = 横浜

つまり、

dataArray[1, 0]

で 日本、

dataArray[1, 1]

で 東京 を取得できます。


見出し行を除外して二次元配列にする

実際にゲーム内で使う場合は、最初の見出し行が不要なこともあります。

その場合は、見出し行を飛ばして読み込みます。

using System.Collections.Generic;
using UnityEngine;

public class CapitalDataLoader : MonoBehaviour
{
    string[,] dataArray;

    void Start()
    {
        TextAsset textData = Resources.Load<TextAsset>("capitalQuiz");

        string[] lines = textData.text.Split('\n');

        List<string> cleanLines = new List<string>();

        foreach (string line in lines)
        {
            string cleanLine = line.Trim();

            if (cleanLine != "")
            {
                cleanLines.Add(cleanLine);
            }
        }

        int rowCount = cleanLines.Count - 1;
        int columnCount = cleanLines[0].Split(',').Length;

        dataArray = new string[rowCount, columnCount];

        for (int row = 1; row < cleanLines.Count; row++)
        {
            string[] values = cleanLines[row].Split(',');

            for (int column = 0; column < columnCount; column++)
            {
                dataArray[row - 1, column] = values[column];
            }
        }

        Debug.Log(dataArray[0, 0]);
        Debug.Log(dataArray[0, 1]);
    }
}

このコードでは、次の部分で1行目を飛ばしています。

for (int row = 1; row < cleanLines.Count; row++)

ただし、配列に入れるときは、

dataArray[row - 1, column] = values[column];

としています。

これは、テキストファイル上の2行目を、配列の0行目に入れるためです。

その結果、配列の中身は次のようになります。

dataArray[0, 0] = 日本
dataArray[0, 1] = 東京
dataArray[0, 2] = 大阪
dataArray[0, 3] = 京都
dataArray[0, 4] = 横浜

見出し行をデータとして使わない場合は、こちらの方法が便利です。


GetLengthで行数・列数を調べる

二次元配列では、行数や列数を調べるときに GetLength() を使います。

dataArray.GetLength(0)

これは行数です。

dataArray.GetLength(1)

これは列数です。

例えば、次のようにすると、すべてのデータを順番に表示できます。

for (int row = 0; row < dataArray.GetLength(0); row++)
{
    for (int column = 0; column < dataArray.GetLength(1); column++)
    {
        Debug.Log(dataArray[row, column]);
    }
}

二次元配列を使うときは、GetLength(0) が行、GetLength(1) が列と覚えておくとよいです。


配列・List・二次元配列の使い分け

最後に、それぞれの使い分けを整理します。

形式向いているデータ配列データ数が決まっている単純な一覧Listデータを追加・削除したい一覧カンマ区切り1行に複数の情報を入れたい場合二次元配列表のように行と列で管理したい場合

例えば、単語リストだけなら、配列やListで十分です。

りんご
みかん
バナナ

敵データのように、1行に複数の情報を持たせたい場合は、カンマ区切りが便利です。

スライム,10,3
ゴブリン,20,5

首都データのように、表形式で管理したい場合は、二次元配列が使いやすいです。

日本,東京,大阪,京都,横浜
アメリカ,ワシントンD.C.,ニューヨーク,ロサンゼルス,シカゴ

注意点:本格的なCSVとは少し違う

今回紹介した方法では、カンマで単純に分けています。

string[] values = line.Split(',');

そのため、データの中にカンマが含まれる場合は注意が必要です。

例えば、

ワシントン, D.C.

のようにデータの中にカンマが入っていると、そこで分割されてしまいます。

今回のサンプルでは、その問題を避けるために、

ワシントンD.C.

のようにカンマを使わない書き方にしています。

簡単なゲームデータや学習用のデータであれば、今回の方法で十分使えます。

ただし、本格的なCSVファイルを扱う場合は、CSV専用の読み込み処理を使った方が安全です。


まとめ

今回は、Resources.Load を使ってテキストファイルを読み込み、配列・List・二次元配列として扱う方法を紹介しました。

ポイントは次の通りです。

Resourcesフォルダにテキストファイルを入れる
TextAssetとして読み込む
.textで中身を取得する
Split('\n')で1行ずつ分ける
Split(',')でカンマごとに分ける
Trim()で余計な空白や改行を取り除く
Listに入れると扱いやすい
二次元配列にすると表形式のデータを扱いやすい

テキストデータを読み込めるようになると、スクリプトの中に大量のデータを書かずに済みます。

特に、

  • 単語リスト

  • クイズデータ

  • 敵データ

  • 会話データ

  • ステージ設定

などを扱うときに便利です。

まずは、1行に1つの単語を書いた簡単なテキストファイルから試してみると、Resources.Load によるテキスト読み込みの流れが理解しやすいと思います。


Unity初心者向けの記事をテーマ別にまとめています。

▼ Unity初心者向け記事まとめはこちら


こちらのマガジン「ミニゲーム作成講座 全8回セット」でもシーンの切り替えなどを活用して、初心者でも知識ゼロから作れるミニゲーム作成講座を紹介しています。

さらにステップアップの「スマホで遊ぶジャンプゲーム 8回セット」のマガジンもぜひご活用ください。



ファイブボックスでは、スクラッチやUnityの個別指導のオンラインレッスンを行っています。

ご興味のある方は当サイト、オンラインレッスンから、無料体験授業へお問い合わせ下さい。

いいなと思ったら応援しよう!

ファイブボックス よろしければ応援お願いします! いただいたチップはクリエイターとしての活動費に使わせていただきます!