皆さん、こんにちは。
お昼のUnity3分クッキングの時間です。
今回はUnityエディタを使ってJsonファイルを作っていきます。
それでは調理を開始していきましょう。
この記事にはUnity2017.1.1f1を使用しています。
下準備
さて、今回Jsonファイルを作っていくわけですが、そのためのエディタも拡張して作っていきますよ。
Jsonファイルを作るだけならば、わざわざUnityをつかなくとも、コンソールのアプリケーションでも作ったほうが早い、と思う方も多いと思います。
ぶっちゃけその通りだと思います。
ですが、状況によってはUnityエディタ上でJsonファイルを作ることが作業の効率が良い場合もありえます。
そんな時にぜひともご利用ください。
それでは、材料です。
- Unity
ネット上でダウンロードしてください。- ちょっとしたC#の知識
分からないコードはググってください。- 熱き正義の心
コードを組む以上、必ず用意してください。
ご用意いただけたでしょうか。
それでは調理に入りましょう。
Jsonのデータになるクラスを作成
まずJsonデータになるクラスを作っていきましょう。
データの型としては、クラスでも構造体でもどちらでもお好みの方お使いください。
ですが必ずSystem.Serializable
のアトリビュートを付けることを忘れないでくださいね。
そして、Jsonのパラメータとして使う変数にSerializeField
のアトリビュートを付けてください。
今回はクラスと構造体の合わせたものを用意してみました。
JsonData.cs
using UnityEngine; [System.Serializable] public class JsonData { [SerializeField] public PersonalData[] party = null; } [System.Serializable] public class PersonalData { [SerializeField] public string name = string.Empty; [SerializeField, Range(1, 100)] public int life = 1; [SerializeField, Range(0, 50)] public int attack = 0; [SerializeField] public AccessoryData[] accessories = null; } // class PersonalData [System.Serializable] public struct AccessoryData { [SerializeField] public string name; [SerializeField, Range(0, 10)] public int defense; } // AccessoryData
このクラスから作られるJsonデータは変数名がそのままパラメータ名になります。
私は普段は変数名に付け合わせとしてm_
を頭に付けるのですが、味がしつこくなるため今回は使用致しません。
エディタウィンドウを作成
つづいて、Jsonデータを作成するUIとしてエディタウィンドウを作っていきましょう。
エディタウィンドウとしては指定したパラメータをJsonファイルとして吐き出すだけのシンプルなものを作ります。
そんなときに便利な調味料がScriptableWizard
です。
このScriptableWizard
をサッと掛けるだけで、簡単にシリアライズした変数とボタンを表示するための下味を付けることが出来ます。
ScriptableWizardスクリプトリファレンス*
https://docs.unity3d.com/ScriptReference/ScriptableWizard.htmldocs.unity3d.com
それではScriptableWizard
を使って調理していきます。
エディタ用の関数を使うので、Editorフォルダ内にスクリプトを作ることをお間違いなく。
JsonEditorWindow.cs
using UnityEngine; using UnityEditor; public class JsonEditorWindow : ScriptableWizard { [SerializeField] private JsonData m_jsonData = null; [MenuItem( "Tool/JsonEditor" )] public static void Open() { DisplayWizard<JsonEditorWindow>( "JsonEditor", "Save" ); } /// <summary> /// ScriptableWizardのメインとなるボタンが押された際に呼ばれるよ! /// 今回の場合はDisplayWizardの第二引数で指定した"Save"ボタンが押されたとき。 /// </summary> private void OnWizardCreate() { string json = JsonUtility.ToJson( m_jsonData ); string path = EditorUtility.SaveFilePanel( "名前を付けてJsonを保存しよう", "", "Setting", "json" ); System.IO.File.WriteAllText( path, json ); // プロジェクトフォルダ内に保存された際の対応. AssetDatabase.Refresh(); } } // class JsonEditorWindow
Saveボタンを押すことで、保存ダイアログが開かれてファイルを保存できるようになりました。
今回はUnityヘルパー産のEditorUtility.SaveFilePanel()
を使って保存ダイアログを表示する調理をしました。
ほかにもUnityヘルパー産の関数の中にはEditorUtility.SaveFilePanelInProject()
というものもあります。
EditorUtility.SaveFilePanelInProject()
の場合は、同じように保存ダイアログを出すことが出来るのですが、現在のUnityプロジェクトフォルダ外に保存しようとするとエラーメッセージが出ます。
Unityプロジェクトフォルダ内に保存しなくてはいけない場合は、こちらのほうを最寄りのスーパーなどでお買い求めください。
Jsonの盛り付けを整える
さて、先ほどできたJsonデータをお皿に盛りつけてみましょう。
{"party":[{"name":"上カルビ","life":50,"attack":20,"accessories":[]},{"name":"冷麺","life":0,"attack":0,"accessories":[{"name":"酢","defense":5},{"name":"玉子","defense":3}]}]}
もちろんこのままでもお召し上がりいただけるのですが、少し盛り付けを整えてみましょう。
料理である以上、見た目も重要です。データ量は増えてしまいますが。
盛り付ける方法は、以前FaceAPIを作っていた際のMicrosoft様の盛り付け方法を利用させていただきましょう。
docs.microsoft.com
JsonEditorWindow.cs
/// <summary> /// ScriptableWizardのメインとなるボタンが押された際に呼ばれるよ! /// 今回の場合はDisplayWizardの第二引数で指定した"Save"ボタンが押されたとき。 /// </summary> private void OnWizardCreate() { string json = JsonUtility.ToJson( m_jsonData ); json = JsonPrettyPrint( json ); string path = EditorUtility.SaveFilePanel( "名前を付けてJsonを保存しよう", "", "Setting", "json" ); System.IO.File.WriteAllText( path, json ); // プロジェクトフォルダ内に保存された際の対応. AssetDatabase.Refresh(); } private string JsonPrettyPrint( string i_json ) { if( string.IsNullOrEmpty( i_json ) ) { return string.Empty; } i_json = i_json.Replace( System.Environment.NewLine, "" ).Replace( "\t", "" ); System.Text.StringBuilder sb = new System.Text.StringBuilder(); bool quote = false; bool ignore = false; int offset = 0; int indentLength = 3; foreach( char ch in i_json ) { switch( ch ) { case '"': if( !ignore ) { quote = !quote; } break; case '\'': if( quote ) { ignore = !ignore; } break; } if( quote ) { sb.Append( ch ); } else { switch( ch ) { case '{': case '[': sb.Append( ch ); sb.Append( System.Environment.NewLine ); sb.Append( new string( ' ', ++offset * indentLength ) ); break; case '}': case ']': sb.Append( System.Environment.NewLine ); sb.Append( new string( ' ', --offset * indentLength ) ); sb.Append( ch ); break; case ',': sb.Append( ch ); sb.Append( System.Environment.NewLine ); sb.Append( new string( ' ', offset * indentLength ) ); break; case ':': sb.Append( ch ); sb.Append( ' ' ); break; default: if( ch != ' ' ) { sb.Append( ch ); } break; } } } return sb.ToString().Trim(); }
これでつくられたJsonデータをお皿に盛りつけるとこのようになります。
{ "party": [ { "name": "上カルビ", "life": 50, "attack": 20, "accessories": [ ] }, { "name": "冷麺", "life": 30, "attack": 40, "accessories": [ { "name": "酢", "defense": 5 }, { "name": "玉子", "defense": 3 } ] } ] }
繰り返しになりますが、情報は美味しそうに見えるようになりますが、データ量はスペースや改行が追加した分確実に増えますので、使うかどうかお好みで。
ScriptableObjectに入力情報を保存
さて、このまま食卓に出してもいいのですが、もう少し細部にこだわっていきましょう。
今の状態では、エディタウィンドウを閉じると、入力していたデータが消えてしまいます。
これでは少々食べ辛いので、入力した情報をScriptableObject
に保存するようにしましょう。
まずScriptableObject
用のクラスを作成しましょう。
JsonScriptableObject.cs
using UnityEngine; public class JsonScriptableObject : ScriptableObject { [SerializeField] private JsonData m_jsonData = null; public JsonData Json { get { return m_jsonData; } set { m_jsonData = value; } } } // class JsonScriptableObject
このScriptableObject
用のスクリプトをエディタウィンドウが開いた瞬間に読み込み、ウィンドウのパラメータを書き換えた場合に情報を書き込むようにしましょう。
JsonEditorWindow.cs
[SerializeField] private JsonScriptableObject m_jsonScriptableObject = null; private static readonly string SAVE_ASSET_PATH = "Assets/Editor/JsonScriptableObject.asset"; [MenuItem( "Tool/JsonEditor" )] public static void Open() { var window = DisplayWizard<JsonEditorWindow>( "JsonEditor", "Save" ); var saveAsset = AssetDatabase.LoadAssetAtPath<JsonScriptableObject>( SAVE_ASSET_PATH ); // ファイルが存在しないときには作成しよう。 if( saveAsset == null ) { saveAsset = CreateInstance<JsonScriptableObject>(); AssetDatabase.CreateAsset( saveAsset, SAVE_ASSET_PATH ); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } window.m_jsonScriptableObject = saveAsset; window.m_jsonData = saveAsset.Json; } /// <summary> /// パラメータを更新した時に呼ばれるよ! /// </summary> private void OnWizardUpdate() { if( m_jsonScriptableObject != null ) { m_jsonScriptableObject.Json = m_jsonData; } }
これでウィンドウを再度開いた場合にも、先ほど記述していた情報が残るようになり、とても食べやすくなってお子さんも喜ぶと思います。
外部Jsonファイルを読み込む
最後に逆にJsonファイルを読み込んで、エディタのパラメータに表示する機能を付け合わせとして用意して品数を増やしてみましょう。
ScriptableWizard
には、引数を追加することでデフォルトのボタンとは別にもう1つボタンを付けることが簡単にできます。
忙しい奥様にはぴったりの機能です。
JsonEditorWindow.cs
[MenuItem( "Tool/JsonEditor" )] public static void Open() { var window = DisplayWizard<JsonEditorWindow>( "JsonEditor", "Save", "Load" ); var saveAsset = AssetDatabase.LoadAssetAtPath<JsonScriptableObject>( SAVE_ASSET_PATH ); // ファイルが存在しないときには作成しよう。 if( saveAsset == null ) { saveAsset = CreateInstance<JsonScriptableObject>(); AssetDatabase.CreateAsset( saveAsset, SAVE_ASSET_PATH ); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } window.m_jsonScriptableObject = saveAsset; window.m_jsonData = saveAsset.Json; } /// <summary> /// ScriptableWizardのサブとなるボタンが押された際に呼ばれるよ! /// 今回の場合はDisplayWizardの第三引数で指定した"Load"ボタンが押されたとき。 /// </summary> private void OnWizardOtherButton() { string path = EditorUtility.OpenFilePanel( "Jsonファイルを開く", "", "json" ); string json = System.IO.File.ReadAllText( path ); JsonData loadedJsonData = null; // Jsonとは異なるファイルを読んだとき用の対策。 try { loadedJsonData = JsonUtility.FromJson<JsonData>( json ); } catch( System.Exception i_exception ) { Debug.LogError( i_exception ); loadedJsonData = null; } if( loadedJsonData != null ) { m_jsonData = loadedJsonData; OnWizardUpdate(); } }
追記
※ 2017/10/17 追記
JsonScriptableObject
の情報がUnityを閉じてしまうと保存されない不具合がありました。
以下の一文を追加することで修正することができます。
JsonEditorWindow.cs
private void OnWizardUpdate() { if( m_jsonScriptableObject != null ) { m_jsonScriptableObject.Json = m_jsonData; EditorUtility.SetDirty( m_jsonScriptableObject ); } }
エンディング
いかがでしたでしょうか。
ジャスト3分で美味しいJsonデータが出来たと思います。
レシピのまとめは以下に記述しておきますので、明日のお昼ご飯にご利用ください。
来週は美味しい焼肉の焼き方についてですが、一部地域ではご覧いただけないのでご了承ください。
それではまた来週にお会いしましょう。