徒然エンジニアブログ

徒然エンジニアブログ

理系東大生がプログラミングを中心に様々なことについて情報発信していきます!

【Unity】エクセルのデータをScriptableObjectに格納する方法

f:id:turedureengineer:20181209180045j:plain

はじめに

ゲームを作っているとデータなどをエクセルで管理したい場合があると思います。
例えばレベルごとの強さなどのデータです。
もちろんスクリプトの中に直接書くこともできますがそれだと変更などをするのが大変です。
またプランナーとエンジニアで仕事を分担している時などもデータをエクセルで管理すると楽です。


今回はエクセルのデータをScriptableObjectに格納してそれを参照するという方法でやっていきたいと思います。

NPOIのインストール

https://www.nuget.org/packages/NPOI/
ここのページに移動して、右にあるDownload packageをクリックしてインストールしてください。

そうすると「npoi.2.4.1.nupkg」というファイルが得られます。
多くの人はそのままクリックしても、開くためのアプリケーションがないと言われて開けません。

ではどうするのかというと拡張子をzipに変えればいいだけです。
というのもnupkgというのはzipの親戚のようなものだからです。

そのため拡張子をzipに変えてあげることで解凍できるようになります。

そうするとこのようになります。
必要なのはllbフォルダの中にあるnet20というフォルダです。

これをunityのAssetsの下に置きます。
これで準備完了です。

ScriptableObjectの実体を作る

ファイル名はSampleSO.csとしておきます。(SOはScriptableObjectの略です)

このファイルはどこにおいても構いません。

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

public class SampleSO : ScriptableObject
{
    public List<float> power;
}

これだけです。
保持しておきたい値を今回はリストで保持します。




scriptableObjetを作成するスクリプトを書く

先ほどScriptableObjectの実体を作ったのでそれを元にしてScriptableObjectを作成するスクリプトを書きます。
Asset以下に「Editor」という名前でフォルダを作り、そこの中にCreateScriptableObject.csという名前のファイルを作ります。

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

public class CreateScriptableObject
{
    private static SampleSO instance;

    [MenuItem("ScriptableObject/Create PowerAsset")]
    static void CreatePowerAsset()
    {
        //インスタンスを生成
        instance = ScriptableObject.CreateInstance<SampleSO>();
        //アセットを作成
        AssetDatabase.CreateAsset(instance, "Assets/SableObjects/Powerdata.assetcript");
        AssetDatabase.SaveAssets();
    }


    [MenuItem("Editor/ReadExcel")]
    public static void Main()
    {
        instance.power = ExcelRead.ReadBookInfo("Assets/Excel/sample.xlsx");
        EditorUtility.SetDirty(instance);
        AssetDatabase.SaveAssets();
    }

}

関数の上に[MenuItem("ScriptableObject/Create PowerAsset")]とありますが、これは


f:id:turedureengineer:20190309011844p:plain

こんな感じで上にScriptableObjectといった項目ができて、そこを押すことで任意の関数を実行させることができます。
なおスクリプトを書いたあと一回実行しないと現れません。

まずは先ほどのSmapleSOのインスタンスを作ります。
そしてそれを元にアセットを作ります。

このアセットの中にデータが入っているので見失わないようにしましょう。
そのため今回はAssets以下にScriptableObjectsというフォルダを作って、その中に保存しています。

Main関数ではインスタンスのpowerにExcelReadファイルのReadBookInf関数を使って読み取った値を入れます。
これに関しては次に実装します。


そして保存しています。
SetDirty(instance)をしないと変更が検知されません。

エクセルで読み込む

ExcelRead.csとしてEditorフォルダの中に入れます。
中身はこんな感じです。

using System;
using System.IO;
using System.Globalization;
using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;
#endif

using NPOI.HSSF.UserModel;
using NPOI.XSSF.UserModel;
using NPOI.SS.UserModel;
using System.Collections.Generic;
using System.Collections;

public class ExcelRead : AssetPostprocessor
{
    public static List<float> ReadBookInfo(string path)
    {
        FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
        IWorkbook book = new XSSFWorkbook(fs);

        List<float> power = new List<float>();

        ISheet sheet = book.GetSheetAt(2);
        for (int i = 2; i < 100; i++)
        {
            IRow row = sheet.GetRow(i);
            ICell cell = row.GetCell(2);
            power.Add((float)cell.NumericCellValue);
        }
        return power;
    }
}

ReadBookInfo関数はパスを受け取ってそこに書いてある値をリストにして返します。
GetCell()の値を変えることで好きな場所の値を取ってくることができます。


エクセルのシートの二枚目を参照しているのもわかるともいます。
そして2行目から100行目までの二列目をリストに入れていっています。

使い方

さてこれで実装は終わりなので使い方を書いていきたいと思います。
まずは一回ゲームを実行します。(すぐに終了しても大丈夫です。)
すると先ほど行ったように上にScriptableObjectとEditorというのができます。
まずはScriptableObjectのCreate PowerAssetをクリックします。
すると、指定した場所(今回はAssets/SableObjects)にScriptableObjectができます。

今のぞいてみても何もデータが入っていないことがわかります。
次にEditorのReadExcelをクリックして、データを読み込みます。
すると先ほどからだったところにデータが入っていることがわかると思います。


もちろん元となるエクセルデータは指定の場所に置いておいてください。

参照の仕方

下のように書いてインスペクタにドラッグ&ドロップしましょう。

[SerializeField] private SampleSO sampleSO;

としてsampleSO.powerとすればいいです。