【Unity】DefaultAssetを使ってディレクトリを指定する

本記事は、[サムザップ #1 AdventCalendar 2020](https://qiita.com/advent-calendar/2020/sumzap1)の12/10の記事です。
12/9の記事は、[@kurosawa_tomokazu](https://qiita.com/kurosawa_tomokazu)さんの[ムービー再生中にFPSを落とさせない工夫](https://qiita.com/kurosawa_tomokazu/items/7c04052246b338dc4873)でした。

# はじめに
UnityでEditor拡張やScriptableObjectを使ってツールを作る時に、
あるディレクトリの中にあるアセットに対して何かしらの処理を行うために、そのディレクトリの中にあるアセットのパスの一覧を取得したいという場面に出くわすことは、割とよくあると思います。

この時、起点となるディレクトリのパスをソースコードやScriptableObjectなどに文字列として定義してしまいがちになりますが、あまり良い方法とはいえません。

ディレクトリのパスが変わってしまった場合、定義している文字列も変える必要があるからです。
ソースコード内に定義してしまっていれば、主にソースコードを書いているエンジニアしか変えることができませんし、ScriptableObjectに定義していたとしても、ディレクトリのパスの文字列を取得してくるという一手間が掛かってしまいます。

では、どうすれば良いでしょうか。
その答えは、[DefaultAsset](https://docs.unity3d.com/ja/current/ScriptReference/DefaultAsset.html)にあります。

# DefaultAssetとは
[Unityのドキュメント](https://docs.unity3d.com/ja/current/ScriptReference/DefaultAsset.html)を見ると、
> DefaultAsset is used for assets that do not have a specific type (yet).

とあり、
型が（まだ）決まっていないアセットは、DefaultAssetとして扱われるようです。

具体的には、Unityプロジェクト内のディレクトリやExcelファイル等のUnityのアセット以外のアセットが、DefaultAssetとして扱われます。

DefaultAsset型のフィールドをUnityエディタに表示させると、DefaultAssetをD&Dで指定したりObject Pickerから選択したりすることができるようになります。
![SnapCrab_NoName_2020-12-9_3-32-53_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200337/b567dae7-b9d2-b453-7987-75e71f9c26c0.png "hoge")




# DefaultAssetを通してディレクトリのパスを取得する
DefaultAssetは、Unity.Objectを継承しているので、
[AssetDatabase.GetAssetPathメソッド](https://docs.unity3d.com/ja/current/ScriptReference/AssetDatabase.GetAssetPath.html)でDefaultAssetのパス（Assetsディレクトリ以下の相対パス）を取得することができます。

DefaultAssetを通してディレクトリのパスを取得するということをScriptableObjectとEditorWindowで行うとどうなるかを例として挙げます。

## ・ScriptableObjectでの例
```c#:DirectoryInfo.cs
using UnityEditor;
using UnityEngine;
using System.IO;

public class DirectoryInfo : ScriptableObject
{
    public DefaultAsset DirectoryAsset;

    /// <summary>
    /// ディレクトリのパスを取得する
    /// </summary>
    public string GetDirectoryPath()
    {
        if (DirectoryAsset == null) return null;

        // DefaultAssetのパスを取得する
        string path = AssetDatabase.GetAssetPath(DirectoryAsset);
        if (string.IsNullOrEmpty(path)) return null;

        // 取得したパスがディレクトリのパスの時だけ、パスを返す
        bool isDirectory = File.GetAttributes(path).HasFlag(FileAttributes.Directory);
        if (isDirectory == false) return null;

        return path;
    }
}
```

## ・EditorWindowでの例
```c#:DirectoryInfoWindow.cs
using UnityEditor;
using UnityEngine;
using System.IO;

public class DirectoryInfoWindow : EditorWindow
{
    private DefaultAsset _directoryAsset;

    [MenuItem("Window/DirectoryInfoWindow")]
    private static void Open()
    {
        GetWindow<DirectoryInfoWindow>();
    }

    void OnGUI()
    {
        // ディレクトリを指定させる
        _directoryAsset = (DefaultAsset) EditorGUILayout.ObjectField("ディレクトリを指定", _directoryAsset, typeof(DefaultAsset), true);
        if (_directoryAsset != null)
        {
            // DefaultAssetのパスを取得する
            string path = AssetDatabase.GetAssetPath(_directoryAsset);
            if (string.IsNullOrEmpty(path)) return;

            // ディレクトリでなければ、指定を解除する
            bool isDirectory = File.GetAttributes(path).HasFlag(FileAttributes.Directory);
            if (isDirectory == false)
            {
                _directoryAsset = null;
            }
        }
    }

    /// <summary>
    /// ディレクトリのパスを取得する
    /// </summary>
    public string GetDirectoryPath()
    {
        if (_directoryAsset == null) return null;

        return AssetDatabase.GetAssetPath(_directoryAsset);
    }
}
```

# ディレクトリの中にあるアセットのパスの一覧を取得するには
さらに、上で取得したディレクトリのパスからそのディレクトリの中にあるアセットのパスの一覧を取得したい場合は、
[AssetDatabase.FindAssets](https://docs.unity3d.com/ja/current/ScriptReference/AssetDatabase.FindAssets.html)や[AssetDatabase.GUIDToAssetPath](https://docs.unity3d.com/ja/current/ScriptReference/AssetDatabase.GUIDToAssetPath.html)を使って、

```c#
string[] childAssetPathList = AssetDatabase.FindAssets("", new[] {dirPath})
    .Select(AssetDatabase.GUIDToAssetPath).ToArray();
```
などとすれば、取得できます。


# まとめ
本記事では、ネットでも比較的情報が少ないDefaultAssetについて紹介し、その使いどころの１つとして、Unityプロジェクト内のディレクトリをEditor上でD&DやObject Pickerで指定できるようにするのに使えるということを書きました。
UnityのEditor拡張でツールを開発するとなると、まとまった情報が比較的少ない上に開発期間もそこまで取れないことが多いため、その時知っている事だけを使って開発を進めてしまいがちになりますが、
少しでも使いやすくメンテしやすいツール作りができるようになるために、Editor拡張についての情報を仕入れる時間もしっかり取っていきたいと思いました。

明日は、[@higuchi_yuta](https://qiita.com/higuchi_yuta)さんの記事です。