[unity]エクセルでゲームデータを管理

大元のアイデアはテラシュールブログさんです(かなり昔)。エクセルを自動的に Scriptable Object にして楽々データ管理、2020年版です。
後発ですし、ちまちまと機能追加もしていたら、結構コードが増えました…。

  • マルチシート対応。1クラスマルチシートにも対応
  • クラス内クラスも、エクセルで宣言可能
  • List<> 構造も扱える
  • enum 宣言もエクセルで可能
  • enum やクラスのメンバにコメントを書くことも可能

そもそも Scriptable Object ってなに? という方はこちらの記事も参考にしてください。

今回のエディタ機能は Scriptable Object の欠点部分をなくし、もっと便利に使おうというプロジェクトです。

実行環境

実際にどう使うか確認するために、サンプルのエクセルも入っています。
以後の説明はこのパッケージを使ったものです。解凍し、新しいプロジェクトで Import してください。

ImportXLS1007 ダウンロード
最新は Github にてダウンロードできます。

NPOI ライブラリが必要

エクセルにアクセスするため、NPOI ライブラリを使用しています。
同梱するのはさすがにまずそうなので、申し訳ありませんがパッケージには含まれていません。
Editor/ImportXLS/npoi の中にいれてください。
2020/09 現在のダウンロード先と方法を示しておきます。必要なのは 6 ファイルです。

NPOI.dll
NPOI.OOXML.dll
NPOI.OpenXml4Net.dll
NPOI.OpenXmlFormats.dll

https://www.nuget.org/packages/NPOI/2.5.1
(解凍したフォルダの lib/net45 内)

BouncyCastle.Crypto.dll
https://www.nuget.org/packages/Portable.BouncyCastle/
(解凍したフォルダの lib/net40 内)

ICSharpCode.SharpZipLib.dll
https://www.nuget.org/packages/SharpZipLib/
(解凍したフォルダの lib/net45 内)

ページの右欄、Download Package でそれぞれ入手できます。

無事に入れられた場合、こんな感じになっているはずです。

サンプルエクセルの説明

実際のRPGっぽいサンプルデータです。マップチップと、2つの街のキャラ情報が含まれます。


Scriptable Object を扱うためのクラスメンバです。
必ず一番最初に ID 列を宣言する必要があります(つけないとコンバートされません)

列の型
エクセルから自動的に型を取ろうとも考えたのですが、色々と火種を産むのでやめました。列のプログラム上の型を指定してください。
bool、int、string、float、enum が使えます。

bool
基本は false / true 。空欄は false となり、〇など「なにか文字列があれば」true 扱いです。

int
float
数字。エクセルで =SUM(A1:A2) など計算式を設定していた場合、その結果を取得できます。

string
文字列。エクセルで =TEXT(A1,"###")+TEXT(A2, "###") など式を設定していた場合、その結果を取得できます。

enum
基本は enum:eQuestionCategory と記述しますが、別クラスの enum を使う場合、クラス名.enum名 です。例えば enum:CityData.eMovePattern みたいな。

List<> 構造やサブクラスも可能ですが、ややこしくなるので「その他の仕様」にて。

コメント
#comment
//comment
[[comment]]
これらの記号で記述されていたものをコメントと見なします。列であれば上、enum であれば右に書いてある場合のみ有効です。
コメントはなくても構いません。
背景色は別に黒でなくていいです。サンプルはわかりやすいように色を変えてあります。

テーブル (Scriptable Object)
Scriptable Object のことを本記事ではテーブル、と呼びます。一般的には「表」でしょうか。
SQL などをごにょごにょした経験のある方はそちらの方がネーミング的にしっくりくるかも。

enum
シートにはテーブルだけではなく、列に使った enum を宣言することもできます。
テーブルを記述しなければ、enum だけのシートなんてのも作れます。(使うかどうかはおいといて)

テーブルと enum、enum と enum の間は最低 2 行空けるようにしてください。
空けない場合、エラーログが出てそのシートはコンバートされません。

なお、[ENUM] ではなく [GLOBAL_ENUM] とするとクラスの外に enum が生成されます。
クラスの外なので、他のクラスからも簡単にアクセスできるようになります。

///<summary>
/// eConst
///</summary>
public enum eLang
{
    大きい方,
    小さい方,
};

/// <summary>
/// Table: ScriptableObject
/// </summary>
public class Table : ScriptableObject
{
    ///<summary>
    /// Table Row
    ///</summary>
    [System.Serializable]
    public class Row
・
・
・
}

MapChipシートを変換する

MapChip Scriptable Object に変換する手順です。

  • エクセル TestGame 右クリック - ImportXLS(おそらく一番下)を選択
ImportXLS 設定画面
  • class dir、scriptable object dir は デフォルト のまま
  • ウィンドウ下、真ん中の create MapChip ボタンを押す

正しく作成されると、次のようなウィンドウが表示されます。

自動的に 3 ファイルほど追加されます。これが Scriptable Object を生成したり、アクセスするためのキークラスとなります。詳細については後程説明します。

準備は整ったので、Scriptable Object を作成します。手順は 1 つだけです。

  • TestGame右クリック - Reimport を選択

Console ウィンドウに [ImportXLS] create 'Assets/Resources/MapChip.asset' と表示され、Scriptable Object が生成されます。

エクセル

Scriptable Object

オレンジの部分がコンバート内容です。
Scriptable Object は手で編集できないようにロックがかかっています。
Scriptable Object を手で変更してしまうと、エクセルが更新されるたびに上書きされ変更が消されたり、わけがわからなくなるためです。

Scriptable Object の型となるクラスは MapChip_Table.cs です。テーブルだけではなく、enum の情報なども自動的に取り込まれています。
エクセルに記述されていたコメントも、ソースコードに反映されます。
(エクセルにコメントをかかなければ、ソースコードにコメントが入ることもありません)

エクセルにコメントなし

コメントあり

全シートを変換する

先ほどと、手順はたいして変わりません。

  • エクセル TestGame 右クリック - ImportXLS を選択
  • CREATE ALL を押す
  • TestGame を 右クリック - Reimport

また、エクセルを変更した後も自動的に Reimport が走り、Scriptable Object が更新されます。
通常はこちらの自動更新に任せておけば大丈夫です。

まれに自動更新されない場合があります。その場合今回のように、手動で Reimport しましょう。

自動生成されるクラスについて

MapChip を例に説明します。

MapChip_Table.cs

Scriptable Object のテーブルの形(列)を決めるクラスです。プログラムでは Row(行)クラスを使ってデータにアクセスします。

MapChip_Table test = Resources.Load<MapChip_Table>("MapChip");

foreach (var entity in test.Rows)
{
    Debug.Log($"{entity.ID}: {entity.Category}");
}

Count
データの最大数を返します。

Rows
全行のデータを List<> で取得します。

GetRow(index)
配列の index 番目の行データを返します。

FindRowByID(id)
ID が id の行データを返します。

FindRowBy??????(val)
以下のように、列の後ろに * をつけると、FindRow メソッドが自動的に追加されます。
(下の例では FindRowByWord(eLang val) というメソッドが追加される)

MapChip.cs

データをシングルトンで扱いたい場合に使えるヘルパークラスです。
これを使えば、どのシーンでもインスタンスではなく MapChip.XXXX() でデータを呼び出せるので、扱いが格段に楽になります。

MapChip_Table test = Resources.Load<MapChip_Table>("MapChip");
MapChip.SetTable(test);

foreach (var entity in MapChip.Rows)
{
    Debug.Log($"{entity.ID}: {entity.Category}");
}

なお、このクラスがいらない場合、設定画面で create accessor のチェックを外せば、生成されません。

MapChip_Importer.cs

エクセルが更新されると unity はその情報を検知し、OnPostprocessAllAssets() を呼び出します。
この時にエクセルのシート情報から全て Scriptable Object に作っています。
自動で動作するので、このクラスを意識してアクセスすることはないでしょう。

なお、readonly な Scriptable Object にしているのはこのコードの以下の箇所です。

data.hideFlags = HideFlags.NotEditable;

その他の細かい使い方について

その他の細かい使い方については、こちらの記事をご覧ください。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA