(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

Scripted Importerを使ってUnityが対応していない拡張子のファイルへの対応【Unity】【エディタ拡張】【Unite 2018 Tokyo】


このエントリーをはてなブックマークに追加


この記事でのバージョン
Unity 2017.4.6f1


はじめに

今回はUnityのScripted Importerという機能を使って、

Unityが対応していない拡張子のファイルへの対応を行おうというお話です。


イメージとしては以下のような感じ。(.sampleという拡張子のファイルを直接ScriptableObjectに変換)


f:id:kan_kikuchi:20180710093702j:plain


なお、『Unite 2018 Tokyo』「エディター拡張マニアクス2018」を参考にさせてもらってます。



講演者:安藤 圭吾(フィールドエンジニア|ユニティ・テクノロジーズ・ジャパン合同会社)

【こんな人におすすめ】
・エディター拡張を触っている人
・Unityエディター拡張入門 (http://anchan828.github.io/editor-manual/)の内容が理解できる人
・エディター拡張の最新情報が気になる人


【受講者が得られる知見】
・エディター拡張の最新機能



Unityにおけるファイルとアセット

Unityは画像にしろ音源にしろ、ファイルをそのまま使うのではなく、

アセットというUnityで扱いやすいものに加工して使っています。


f:id:kan_kikuchi:20180707164852j:plain
【Unite Tokyo 2018】エディター拡張マニアクス2018 - YouTube


しかし、Unityが対応していないファイル(拡張子)はデフォルトアセットという意味を持たない(使えない)

アセットにされてしまうので、PrefabやScriptableObjectなどの他のアセットに加工する必要があります。


つまり対応していないファイルをUnityで使おうとすると、

使えないアセットと、それから生成した使えるアセットの2つが存在してしまう

という事になります。


f:id:kan_kikuchi:20180707164913j:plain
【Unite Tokyo 2018】エディター拡張マニアクス2018 - YouTube


これがScripted Importerを使えば、

未対応のファイルを直接、使えるアセットに変換する事が出来るのです。


f:id:kan_kikuchi:20180707164955j:plain
【Unite Tokyo 2018】エディター拡張マニアクス2018 - YouTube


なお、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に変換されます。


f:id:kan_kikuchi:20180710093702j:plain


なお、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);

  }

}

f:id:kan_kikuchi:20180710103141g:plain


また、通常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();
  }

}

f:id:kan_kikuchi:20180710104542j:plain


なお、CustomEditorを使うという部分は通常の場合と同じです。


おわりに

Unity未対応のファイルを使いたい時に余計なファイルが増えないのは地味に嬉しいですね。

また、「違う種類のデータだけど全部json形式」みたいな時に、

「拡張子を変えてデータごとに違うScriptableObjectに自動で変換」という使い方も出来そうです。