エクセルは誰でも使えるデータ生成ツール
一部のプログラマーには嫌われることの多いエクセルですが、データ作成にあたっては様々な利点があります。
- 入力が簡単で手早くできる
- プログラマー以外でも大抵の人が使える
- 計算式マクロやソート・フィルタが使えるのでデータを比較・検討することも容易
嫌われる1番の理由は Git や Svn などで履歴の比較が難しい点でしょうか。
ただ、このエクセルデータをそのまま unity ゲームに入れることは出来ません。
これを自動化するためのツール XlsToJson を紹介します。
ToJson としていますが、Scriptable Object にも対応しています。
以前紹介した ImportXLS の拡張ですが、随分変えてしまったので別のものとして紹介します。
unity でデータを作る方法
その前に、unity でデータを作る一般的な方法について簡単に説明します。
プログラムでデータクラスを作成する
例としてキャラクターのデータを作ります。
[System.Serializable] public class Row { public int CharacterNo; public string CharacterName; public float Size; public List<int> FriendNo = new List<int>(); public Sex Sex; }
キャラクター番号、名前、サイズ、友達の(キャラクター)番号、性別。
性別は enum で定義しています。
public enum Sex { Female, Male, Unknown, }
現実的なデータは int, string, float などの単純な型だけでなく、List や enum なども含まれるでしょう。
エクセルから手作業でデータを取り込んでいた場合、もうこの時点で面倒になるはずです。
ツールでは上記の宣言をエクセルから自動生成します。(DataClass)
Dictionary は対応していません。JsonUtility や ScriptableObject がそもそも Dictionary を許容してないためです。
Json 形式
データクラスが出来ていれば、json については JsonUtility で比較的簡単に読み書きが可能です。
他への転用も効きやすいですし、一番メジャーな形式ではないでしょうか。
var row = new Row() { CharacterNo = 1, CharacterName = "Jsan", Size = 1.0f, Sex = Sex.Male } // Json Text に変換 string jsontext = JsonUtility.FromJson<Row>(row, true); // Text からデータに変換 var row2 = JsonUtility.ToJson(row);
JsonUtility では複数のデータを持ちたい場合に List が使えないため、ダミークラスを作ってその中に List のメンバーを作るという手間をかける必要があります。軽さゆえの制約?
[System.Serializable] public class Wrapper { public List<Row> Rows = new List<Row>(); } var json = File.ReadAllText("sample.json", System.Text.Encoding.UTF8); var data = JsonUtility.FromJson<Wrapper>(json);
Scriptable Object 形式
uinty 固有の形式でアクセスは速い(と、言われている)、インスペクタで確認・編集が可能という固定データ向きのフォーマットですが、読み込みはともかく書き出しが面倒です。
また、インスペクタでのみデータを編集するのも不安です。
XlsToJson ではデータ作成・編集は全てエクセルで行い、最終段階で ScriptableObject を自動書き出しするようにしています。
使い分け
考えるのが面倒であれば全て Json にしておくとデータ更新時の差分も取れていいかな? というのが個人的な感想です。
よほど大容量であれば Scriptable Object も悪くはなさそうです。
(XlsToJson を使う場合、インスペクタで編集可能な利点はありません。エクセルでより自由度の高いエディットが可能だからです)
XlsToJson
ダウンロード(リポジトリ)
unity のサンプルプロジェクトになっています。
サンプルプロジェクトの動作チェック
GitHub から取得した環境を unity で開きます。
Asset/Sample.xlsx(サンプルデータです)を右クリックし、XlsToJson Settings... を選択
デフォルト値のまま、左下の CREATE Importer ボタンを押します。
Asset/Class_Character.cs
Asset/Class_Stage.cs
データクラスの型を定義するコードです。
このクラスによって、エクセルの表を List<Row> という型で読み書きできるようにします。
(表は黄色い部分)
Asset/Character.cs
Asset/Stage.cs
先ほどの方法ではデータのインスタンス(data, data2)を管理する必要があり、少々面倒です。
Character.cs、Stage.cs はシングルトンインスタンスを内包しているので、どこからでもデータにアクセス可能になります。
Tools/XlsToJson/[Create] JsonData
Asset/Resources にエクセルで定義されたテーブルを Json Data として出力します。
[Create] ScriptableObject の場合、Scriptable Object が作成されます。
実際のコードでデータを表示してみる
ここからは、作成したデータの使い方。
Json と Scriptable Object 両方の使い方を提示します。[Create] JsonData と [Create] ScriptableObject を事前に実行しておいてください。
Class_Character、Class_Stage クラスを使った表示の仕方
UsageTable.cs のコードを抜粋します。
(Json) var jsontext = Resources.Load<TextAsset>("Data_Character"); var data = Class_Character.CreateInstance(); data.SetRowsByJson(jsontext.ToString()); foreach (var row in data.Rows) { Debug.Log($"{row.ID} {row.CharacterName} {row.Sex}"); }
(Scriptable Object) var obj = Resources.Load<Object>("Data_Character"); var data2 = obj as Class_Character; foreach (var row in data2.Rows) { Debug.Log($"{row.ID} {row.CharacterName} {row.Sex}"); }
適当な GameObject にアタッチし実行すると、コンソールで確認することができます。
Character、Stage クラスを使った表示の仕方
先ほどの方法ではデータのインスタンス(data, data2)を自前で管理する必要があり、実際に運用を始めると少々面倒です。
Character、Stage クラスはシングルトンインスタンスを内包しているので、どこからでもデータにアクセスできます。
コードの記述方法も、Json、Scriptable Object で同一となり、スッキリしています。
クラス Asset/UsageAccess.cs の抜粋です。
(ForEach の部分は前述の foreach と同じことを1行で書いただけ)
(Json) var jsontext = Resources.Load<TextAsset>("Data_Character"); Character.SetTable(jsontext); Character.Rows.ForEach( (row) => Debug.Log($"{row.ID} {row.CharacterName} {row.Sex}") );
(Scriptable Object) var obj = Resources.Load<Object>("Data_Character"); Character.SetTable(obj); Character.Rows.ForEach( (row) => Debug.Log($"{row.ID} {row.CharacterName} {row.Sex}") );
このクラスが不要な場合、作成をオフにすることもできます。
最低限の使用方法はこんなところです。
以下にもう少し詳しい使用方法について書いておくので、参考にしてください。
コメント失礼いたします。プロジェクトに導入した後に、XLSToJsonSettings > CreateImporterを行うと、「Assets\Class_Character.cs(78,12): error CS0246: The type or namespace name ‘Row’ could not be found (are you missing a using directive or an assembly reference?)」など、Rowがスクリプトに生成されていない旨のエラーメッセージが吐き出されます。エディタのバージョンが異なるのか、特に理由がわからないのですが、良ければ解決方法をご教授いただけないでしょうか?
連投失礼いたします。エディタバージョンは2021.3.11f1で、特にアセットを入れていない新しいプロジェクトにて導入いたしました。エディタ拡張も特に入れていません。
Uni団子さん
こんにちは。
GitHub のサンプルを自分なりに拡張して、試している最中という認識でお答えします。
The type or namespace name ‘Row’ could not be found (are you missing a using directive or an assembly reference?)
とありますので、「自動生成される Class_Character というクラス内の Row という内部クラスが何らかの形でエラーになっており、生成できていない」ように思えます。
問題について、以下のように切り分けていくと問題が見えてくるかもしれません。
1. GitHub のサンプルをインポートするだけで正しく動作するか確認
2. GitHub のサンプルをインポートし、XLSX を XLSToJson Settings… > CREATE Importer してエラーがないか確認
3. その後、Tools > XlsToJson > SampleData.xlsx > Create JsonData してエラーがないか確認
4. 自分なりにエクセルを変更して、2 に戻って確認
また、エディタバージョンですが 2020.3.37f1 までは確認しております。
多分 2021 でも動くとは思うのですが… unity2020 で動作するか念のためご確認くださいますと助かります。
P.S.
私が想定していない使い方でエラーになっている可能性もありますので、もう少し具体的な情報をいただけると、より踏み込んだ回答が出来るかもしれません。
(一番手っ取り早いのは、問題の起きる(が、NDA に引っかからない)テストエクセルを預かる事でしょうか)
返信ありがとうございます。
Unityのエディタバージョンを2020.3.37f1に落としてサンプルプロジェクトをそのまま、UnityHubからOpenしたのですがXLSToJson Settings… > CREATE Importerした時点でRowが生成されていない旨のエラーメッセージが発生いたしました。(私自身のプロジェクトではありません。)
もしかして、私がWindows10のUnityエディタを使用していることと何か関連していますでしょうか。
個人開発ですので特にNDAに引っかかる開発は行っていません。(可能であれば一連の画面録画を送付することも大丈夫です。)真摯なご対応、ありがとうございます。
Uni団子さん
なるほど、なんでしょうね…。私も Windows10 なので、そこは問題ないように思います。GitHub サンプルのままでいきなり動かないのは、ちょっと気持ち悪いですね。
問題が解決するかどうかはわかりませんが…動画、ご提供いただけるのでしたら確認させていただきます。よろしければご検討ください。
(アップしましたら Twitter の DM などいただければ)
TwitterのDMが解放されていなかったので、メールにてリンクを送付させていただきました。リンクの直書き等、失礼いたします。
おっと! 失礼しました。DM 解放しておきました。
また、動画の方も有難うございます。エラーの原因は改行の呪いでした…(GitHub にテキストが上がる際に \r\n -> \n に変換され、テンプレートファイルが誤動作していました)
対処したものを GitHub に上げておきましたので、改めてお試しいただけますでしょうか。
GitHubにそのような変換があるのですね..私も気を付けます。
そしてあらためて確認しましたところ、正常に動かすことができました。迅速なご対応、本当にありがとうございます。