【Unity】Resources.LoadでCSVを扱う

いよいよ12月でっす。
2019の終わりが近づいてまいりました。

令和元年に何かを残したくて日々勉強中です。
年内中に簡単なアプリをアウトプットできるように
頑張ってるのですが、思うように行かないのがプログラムと人生。

無事にできるといいのですが(´`;)

さてさて、勉強中に仕入れた情報を少し書いてみたいと思います。

以前、CSVの扱いを書いたのですが、
ファイルの内容をエクセルで編集する必要があったので、
オープンなフォルダに保存できるようにしていました。

ゲームのフィールドデータやゲーム内容を保存する場合、
オープンなファイルに保存するとユーザーからもアクセスできるので、
内容の編集ができてしまうのは問題があります。

なので、大事なデータはResourcesフォルダー内に保存して
読み書きできるようにするのが、一般的だと思います。

ハックできる人なら簡単に見る事ができるそうですが、
そのへんはスルーします。(;^o^) \(ToT )あんたほんとにそれでいいの


今回は、csvデータからオブジェクトをクローン配置してみます。

内容としては、脱出ルートの表示にしてみようかと思います。

用意したのは、
clone④.jpg
矢印だらけで分かりにくい…  (..*) オハズカシイ・・

フィールドに隠された爆弾があり、条件を満たすと脱出ルートと爆弾が表示される
みたいな感じです。


まず、クローンを生成する為にオブジェクトをプレハブにします。
clone③.jpg
それぞれの4方向のプレハブと爆弾のプレハブを準備します。

クローンオブジェクトは、クリアするまで非アクティブにしたいので、
RootParentの親オブジェクトを作成して、その中にクローンを用意します。

クローンができた所で、親オブジェクトを非アクティブにすれば、
一括でクローンを隠す事ができます。

続いて、エクセルでマップデータを作成します。
クローンは配列で管理するので、配列番号とクローンを合わせます。

今回は、
0=Bomb
1=UP
2=RIGHT
3=DOWN
4=LEFT
空きマス=B

としておきます。

clone⑤.jpg
エクセルで6×6のフィールドデータを作成して、

clone⑥.jpg
csvで保存する際、UTF-8を選択しておくとandroidにも対応できます。

ちなみに空きマスをBとしましたが何でもいいです。
空白を作ると読み込めないので、何かわかるようにしておきます。
今回は、ブランクのBにしました。

読込み時に判別できれば問題なしでっす。


Unityに戻って、CSVファイルをインポートします。
clone⑧.jpg
まず、Resource内にTextDataのフォルダを作ります。

clone⑦.jpg
TextDataのフォルダを開けて、先ほどのCSVファイルをインポートします。


続いて、スクリプトを作成します。


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


public class GameManager : MonoBehaviour
{
public GameObject RootParet; //クローンの親オブジェクト
public GameObject[] RootPanelPrefab; //各オブジェクトのプレハブ

//縦横のポジション座標
private float[] AxisX = { -250, -150, -50, 50, 150, 250 };
private float[] AxisY = { 250, 150, 50, -50, -150, -250 };


private string FilePath = "TextData/RootData"; //CSVファイルのパス



// Start is called before the first frame update
void Start()
{
StartCoroutine(LoadCSV());
}


IEnumerator LoadCSV()
{
TextAsset csvFile = Resources.Load<TextAsset>(FilePath);
StringReader reader = new StringReader(csvFile.text);
List<string[]> csv = new List<string[]>();

//CSVファイルの読み出し
while (reader.Peek() != -1)
{
string line = reader.ReadLine();
csv.Add(line.Split(','));
}
reader.Close();

//データからオブジェクトの選定
for(int y = 0; y < 6; y++)
{
for (int x = 0; x < 6; x++)
{
if (csv[y][x] == "B")
{
continue;
}
else
{
int num = Convert.ToInt32(csv[y][x]);
CreateObject(x, y, num);
}
}
}

RootParet.SetActive(false);

if (RootParet.activeSelf == false)
{
yield return null;
}
}

//オブジェクトの生成
void CreateObject(int x,int y, int num)
{
GameObject root = (GameObject)Instantiate(RootPanelPrefab[num]);
root.transform.SetParent(RootParet.transform, false);
root.transform.localPosition = new Vector3(AxisX[x], AxisY[y], 0);
}
}

StreamReaderを使うので、System.IOを宣言します。
途中でstring型からint型に変換するので、Systemも宣言します。

ファイルのパスは、Resources.LoadでResourcesフォルダまで開いてくれるので、
続きのTextData/RootDataを指定すれば読み込めます。
CSVファイルの拡張子はいりません。

おそらくTextassetとして取り込むので、必要なくなるのでは?
と思っています。ちなみに拡張子を付けると読み込めません。


ファイルから、読み出し座標xyとオブジェクトナンバーを取得して、
ナンバーのみクローンを生成するようにしてみました。

コルーチンでセットしたのは、オブジェクトの生成後に親オブジェクトを
非アクティブにするまで、他の処理を停止する為です。

例えば、クローンに当たり判定を付けていた場合、
フィールド配置のオブジェクトにプレイヤーオブジェクトを重ねて
配置した場合、同時に配置すると当たり判定が出てしまいます。

Destroyなどを呼び出していると、生成と同時に削除されてしまうので、
フィールドオブジェクトを配置して、非アクティブにしてから、
メインオブジェクトを配置すると事故が起こらないかと思います。


少し難点は、StreamReaderでファイルリードをループした所で
再度、リストからオブジェクト生成のループを回している所ですかね。

読込みながら生成を組んでみたのですが、
なぜかCSVの一行目を繰り返し読み込んでしまいました。
仕方がないので生成を分離しました。

この辺りは、今後の課題ですかね~ (~ヘ~;)ウーン

最後にPLAYしてみます。
clone⑨.jpg
ちょっと分かりにくいですが、ヒエラルキーを見るとクローンが生成されています。
親オブジェクトをアクティブにすると…

clone⑩.jpg
無事、生成されております。

後は、クリア判定を用意して親オブジェクトをアクティブ化すればOKかと。
煮るなり焼くなり好きにできます。

同じようなフィールドで複数面あるようなゲームでは、
Sceneを作成するだけで大変になります。

Sceneの切り替えをナンバー化すれば、データの読込みだけになるので、
Textデータからのオブジェクト配置は重要になりそうです。


エクセルでマップデータを作るのも大変なので、
Unityでフィールドデータを編集できるアプリを作っておくと
より楽に複数面の準備ができるようになるかと思います。

プレイSceneの作成に役立ててもらえると嬉しいです。
今回は、この辺で(o・・o)/~マタネェ

この記事へのコメント