Unity パッケージにおけるパスの扱いについて

Unityでパッケージ開発を行っている際に、「パッケージ内で管理しているアセットをロードしたい、コピーしてきたい」と思ったとき、そもそもパッケージ内のアセットのパスの扱いってどうなっているんだっけ…?ってのが分からなかったので、調べたついでにメモとして残しておきます。

パッケージの(アセットデータベースの)パス

プロジェクト内のアセットは、下記のパススキームで参照できます。

Assets/PATH/TO/ASSET

一方で、たとえば com.yucchiy.benri-tool というパッケージ名の、パッケージ内のアセットは、下記のパススキームで参照します。

Packages/com.yucchiy.benri-tool/PATH/TO/ASSET

ちなみにパッケージ名は、 package.jsonname を指します。下図の package.json の場合、 com.yucchiy.benri-tool がパッケージ名です。

C4F67F2500A152DE16762C79A91B5775

パッケージ内のアセットのロードに話を戻します。具体的に、下図の TestPrefab.prefab があるとして、

90E878DED317F471781CF4A762C3F5FE

このプレハブをアセットデータベース経由でロードしてインスタンス化するには、下記のコードで実現できます。

var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(
    "Packages/com.yucchiy.benri-tool/TestPrefab.prefab");
var obj = GameObject.Instantiate(prefab);

また、記事冒頭の要件である、パッケージ内のアセットをプロジェクト配下へコピーするには、アセットデータベース経由では、下記コードで実現できます。

// 上記プレハブをプロジェクトのAssetsフォルダ直下にコピー!
AssetDatabase.CopyAsset(
    "Packages/com.yucchiy.benri-tool/TestPrefab.prefab",
    "Assets/TestPrefab.prefab"
);

アセットデータベース経由ということは、つまりパッケージ内のアセットに .meta が作成されていて、かつ、コピー先のフォルダも、 Assets 配下など、アセットデータベースによって管理されている必要があります。

大抵のケースは事足りるのですが、稀にアセットデータベース管理外のファイルをコピーなどしたい場合があるかもしれません。そういうときは、パッケージ内のファイルを(そのOSの)フルパスで参照し、 System.IO に提供されるAPIでファイル操作すると良いでしょう。

パッケージ内のファイルのフルパスを取得するには Path.GetFullPath を利用します。

// 末尾にチルダ(~)をつけたファイル・フォルダは
// アセットデータベースの管理から外れる(.metaがつかない)
string path = Path.GetFullPath("Packages/com.yucchiy.benri-tool/benri.txt~");
// プロジェクト配下にコピー
File.Copy(path, Path.Combine(Application.dataPath, "..", "benri.txt"), true);

余談: Resourcesフォルダの扱い

ここまで調べてみてPackages/{パッケージ名} がプレフィックスになり、それ以外は通常のUnityプロジェクトにおけるパスの扱いと変わらないのかな?と思い、たとえば Resources の扱いはどうなるんだろう?と気になりました。

そこで、Packages/{パッケージ名} 以下に Resources フォルダを作成し、 Resources.Load 経由でアセットをロードしてみました。

var prefabInResources = Resources.Load(
    "Packages/com.yucchiy.benri-tool/Resources/TestPrefabInResources.prefab");
var obj2 = GameObject.Instantiate(prefabInResources);

結果として、正しくプレハブをロードできない結果となりました。ちなみにパッケージ下に Assets/Resources を掘って、その中にプレハブを置いてロードしてもダメでした。どうやら Resources フォルダの展開はプロジェクト内だけのようです。(迂闊に展開されちゃうと、パッケージ内に Resources フォルダがありその中にデータがあると起動時間等が懸念されるのでこれはこれでよいのですが)

まとめ

Unityのパッケージ内のアセットのパスの扱いと、パッケージ内のアセットをプロジェクトにコピーする方法、余談ではありますがパッケージにおける Resources フォルダの扱いについてまとめました。

参考