この記事でのバージョン
Unity 2017.4.6f1
はじめに
今回はUnityのScripted Importerという機能を使って、
Unityが対応していない拡張子のファイルへの対応を行おうというお話です。
イメージとしては以下のような感じ。(.sampleという拡張子のファイルを直接ScriptableObjectに変換)
なお、『Unite 2018 Tokyo』の「エディター拡張マニアクス2018」を参考にさせてもらってます。
講演者:安藤 圭吾(フィールドエンジニア|ユニティ・テクノロジーズ・ジャパン合同会社)
【こんな人におすすめ】
・エディター拡張を触っている人
・Unityエディター拡張入門 (http://anchan828.github.io/editor-manual/)の内容が理解できる人
・エディター拡張の最新情報が気になる人
【受講者が得られる知見】
・エディター拡張の最新機能
Unityにおけるファイルとアセット
Unityは画像にしろ音源にしろ、ファイルをそのまま使うのではなく、
アセットというUnityで扱いやすいものに加工して使っています。
しかし、Unityが対応していないファイル(拡張子)はデフォルトアセットという意味を持たない(使えない)
アセットにされてしまうので、PrefabやScriptableObjectなどの他のアセットに加工する必要があります。
つまり対応していないファイルをUnityで使おうとすると、
使えないアセットと、それから生成した使えるアセットの2つが存在してしまう
という事になります。
これがScripted Importerを使えば、
未対応のファイルを直接、使えるアセットに変換する事が出来るのです。
なお、Scripted Importerは実験的機能なので、
今後無くなったり仕様が大幅に変わったりする可能性があるので注意が必要です。
また、Unityがサポート済みの拡張子には使えない機能なのであしからず。
使い方
Scripted Importerを使うには、ScriptedImporterを継承したクラスを作成し、
ファイルをアセットに変換する処理を実装する必要があります。
例えば、.sampleという拡張子のファイルを変換するクラスは以下のような感じ。
using UnityEngine; using UnityEditor.Experimental.AssetImporters;//ScriptedImporterを使うのに必要 using System.IO; /// <summary> /// .sampleのファイルをScriptableObjectDataとして使えるように変換するクラス /// </summary> [ScriptedImporter(1, "sample")]//対応する拡張子を登録、1はバージョン、sampleは拡張子 public class SampleImporter : ScriptedImporter { /// <summary> /// .sampleファイルのインポート時、変更時に実行される(ctxにファイルの情報が格納) /// </summary> public override void OnImportAsset(AssetImportContext ctx) { //.sampleのファイルにかかれているテキストを取得 string text = File.ReadAllText(ctx.assetPath); //ScriptableObjectDataを作成、.sampleファイルに書かれていたテキストを設定 ScriptableObjectData data = ScriptableObject.CreateInstance<ScriptableObjectData>(); data.TextData = text; //ScriptableObjectDataをメインアセットとして登録 ctx.AddObjectToAsset("MainAsset", data); //第1引数はアセットIDで、後から変更すると参照が切れたりするので注意 ctx.SetMainObject(data); } }
using UnityEngine; /// <summary> /// stringのデータを一つだけ持ったScriptableObject /// </summary> public class ScriptableObjectData : ScriptableObject { public string TextData = ""; }
上記のSampleImporterをEditorに追いておくと、
.sampleファイルが追加、変更された時に自動でScriptableObjectDataに変換されます。
なお、Inspectorで確認すると上部分にインポーターの情報、
下部分にScriptableObjectData(メインアセット)の情報が表示されるようになります。
(上記の例でHoge.sampleはTestとだけ書かれたテキストファイル。)
拡張
ScriptedImporterはMonoBehaviourと同様に
シリアライズ可能なフィールドを追加すると、Inspector上で設定出来るようになります。
例えば先程のSampleImporterにAdditionalTextというフィールドを追加し、
Inspector上で入力したテキストをデータに追加してみると以下ような感じになります。
using UnityEngine; using UnityEditor.Experimental.AssetImporters;//ScriptedImporterを使うのに必要 using System.IO; /// <summary> /// .sampleのファイルをScriptableObjectDataとして使えるように変換するクラス /// </summary> [ScriptedImporter(1, "sample")]//対応する拡張子を登録、1はバージョン、sampleは拡張子 public class SampleImporter : ScriptedImporter { //データに追加するテキスト public string AdditionalText = ""; /// <summary> /// .sampleファイルのインポート時、変更時に実行される(ctxにファイルの情報が格納) /// </summary> public override void OnImportAsset(AssetImportContext ctx) { //.sampleのファイルにかかれているテキストを取得 string text = File.ReadAllText(ctx.assetPath); //ScriptableObjectDataを作成、.sampleファイルに書かれていたテキストを設定 ScriptableObjectData data = ScriptableObject.CreateInstance<ScriptableObjectData>(); data.TextData = text + AdditionalText;//Inspectorで設定されたテキストも追加 //ScriptableObjectDataをメインアセットとして登録 ctx.AddObjectToAsset("MainAsset", data); //第1引数はアセットIDで、後から変更すると参照が切れたりするので注意 ctx.SetMainObject(data); } }
また、通常Inspector上の表示を拡張する場合はEditorを継承したクラスを作成しますが、
ScriptedImporterの場合はScriptedImporterEditorを使います。
そうする事で、ApplyRevertGUIというメソッドが使えるようになり、
RevertとApplyボタンが簡単に実装出来ます。
using UnityEditor; using UnityEditor.Experimental.AssetImporters; /// <summary> /// SampleImporterのInspectorの見た目を設定するクラス /// </summary> [CustomEditor(typeof(SampleImporter))]//CustomEditorでSampleImporterを指定 public class SampleImporterEditor : ScriptedImporterEditor { //Inspector上のGUIの設定 public override void OnInspectorGUI() { //RevertとApplyボタンを表示、処理も実装 this.ApplyRevertGUI(); } }
なお、CustomEditorを使うという部分は通常の場合と同じです。
おわりに
Unity未対応のファイルを使いたい時に余計なファイルが増えないのは地味に嬉しいですね。
また、「違う種類のデータだけど全部json形式」みたいな時に、
「拡張子を変えてデータごとに違うScriptableObjectに自動で変換」という使い方も出来そうです。