1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Unity】Timelineから参照しているすべてのアセットパスを手に入れたい

Posted at

はじめに

UnityのTimelineを使用していてTimelineAssetが握っている参照アセットをすべて調べたくなりました。
やりたいことは以下です。

  • Timelineが参照しているPrefabやAnimationClipを一覧表示
  • さらにそのPrefabが参照してる各アセットを全表示
    です。

先に見せてしまいますが、Timelineからこのようにアセット名+参照Listが出るようにしたいです。
image.png

ソースコード

今回のアセット構造

Timeline

image.png
タイムラインにはTrackGroup、さらにSubTrackを作り、それぞれにTrackを置きます

image.png
上4つのAnimationTrackはUnity標準のAnimationTrackでAnimationClipをアタッチします。

image.png
下の4つは自作のTrackとClipを配置します。PrefabTrackというものを作成しました。Prefabを3つ入れることができるだけです。
今回は参照関係を知りたいだけなので自作のTrackは特に機能はありません。

ディレクトリ

image.png
Asset>Timelineにタイムラインに関係するものを入れます。

アセットは001と002というIDがあり、Timelineからは001が参照されているのが正しいシチュエーションです。
001と似てるアセットが002にあります。
image.png
アニメーション、マテリアル、Prefabがここに入っています。
002は間違っている想定の場所です。
image.png

そして、TimelineTrackの4番目では002を参照させます
image.png

image.png

各Trackで002が参照されてしまっていることをツールで知れるようにすることが目的です。

やり方

AssetDatabase.GetDependenciesを使用してみる

AssetDatabase.GetDependenciesという依存関係を出してくれるメソッドがUnityであるので使用します。
使い方は以下です。

private string[] GetDependencies(TimelineAsset timelineAsset)
{
    var assetPath = AssetDatabase.GetAssetPath(timelineAsset);
    var dependencies = AssetDatabase.GetDependencies(assetPath, true);
    return dependencies;
}

AssetDatabase.GetDependenciesは第2引数にTrueを入れると再帰的に参照を調べてくれます。
戻ってくる配列に重複はありませんでした。

出力結果はこうなりました
image.png

間違った場所にアクセスしているのが取得できました。
しかし、この方法だと冒頭で書いたやりたいことの
Timelineが参照しているPrefabやAnimationClipを一覧表示
が達成できません。
Timelineから参照関係は知れましたがこのままだとどのアセットに問題があるのかわからない状態です。

Clipから調べる

AssetDatabase.GetDependenciesで達成できなかった理由はアセット名を取得できていなかったこととアセットごとの参照を取得できていない点なのでそれを解決します。

Timelineが含んでいるアセットをすべて取得し、Dictionaryに格納すればうまくいくためそうします。

private void GetDependencies(TimelineAsset timelineAsset)
{
    foreach (var track in timelineAsset.GetOutputTracks())
    {
        GetDependenciesFromTrack(track);
    }
}

まずはTimelineからTrackの数だけループを行います。

/// <summary>
/// TrackのからClipを探し、参照を調べる
/// </summary>
private void GetDependenciesFromTrack(TrackAsset trackAsset)
{
    // Clipの数だけループする
    foreach (var clip in trackAsset.GetClips())
    {
        // シリアライズされたオブジェクト、プロパティを探し、その数だけループさせる
        SerializedObject serializedObject = new SerializedObject(clip.asset);
        SerializedProperty prop = serializedObject.GetIterator();
        while (prop.NextVisible(true))
        {
            // プロパティの種類がUnityEngine.Objectのものだけ調べます。
            if(prop.propertyType == SerializedPropertyType.ObjectReference)
            {
                // プロパティとしてついているスクリプトは参照を調べなくてよいので(今回は)分岐します
                Object referencedObject = prop.objectReferenceValue;
                if(referencedObject != null && referencedObject.GetType() != typeof(MonoScript))
                {
                    // GetDependenciesを使用してプロパティに入れられたアセットの参照を取得します。
                    var assetPath = AssetDatabase.GetAssetPath(referencedObject);
                    // .csは参照から除きます。(今回は)
                    var dependencies = AssetDatabase.GetDependencies(assetPath, true).Where(dependency => !dependency.EndsWith(".cs")).ToList();
                    var assetName = referencedObject.name;
                    if(!_assetDependencies.ContainsKey(assetName))
                    {
                        _assetDependencies[assetName] = dependencies;
                    }
                }
            }
        }

        // SubTrackに関して再帰的に処理します。
        foreach (var subTrack in trackAsset.GetChildTracks())
        {
            GetDependenciesFromTrack(subTrack);
        }
    }
}
foreach (var clip in trackAsset.GetClips())

Clipでループを回します。
そしてClipに入っているアセットをすべて取得します。
取得方法はここです。

SerializedObject serializedObject = new SerializedObject(clip.asset);
SerializedProperty prop = serializedObject.GetIterator();
while (prop.NextVisible(true))
{
    // プロパティの種類がUnityEngine.Objectのものだけ調べます。
    if(prop.propertyType == SerializedPropertyType.ObjectReference)
}

Clipにドラッグアンドドロップできる場所に入っているものがClipに入っているアセットなのでSerializedObject,SerializedPropertyを使用してシリアライズされているプロパティを取得します。
while (prop.NextVisible(true))でプロパティの数だけループします。

// プロパティの種類がUnityEngine.Objectのものだけ調べます。
if(prop.propertyType == SerializedPropertyType.ObjectReference)

ドラッグアンドドロップできるものがアセットと捉えているためこの処理をします。intや他のプロパティはアセット参照とは関係がないため扱いません。

// プロパティとしてついているスクリプトは参照を調べなくてよいので(今回は)分岐します
Object referencedObject = prop.objectReferenceValue;
if(referencedObject != null && referencedObject.GetType() != typeof(MonoScript))
{
    // GetDependenciesを使用してプロパティに入れられたアセットの参照を取得します。
    var assetPath = AssetDatabase.GetAssetPath(referencedObject);
    // .csは参照から除きます。(今回は)
    var dependencies = AssetDatabase.GetDependencies(assetPath, true).Where(dependency => !dependency.EndsWith(".cs")).ToList();
    var assetName = referencedObject.name;
    if(!_assetDependencies.ContainsKey(assetName))
    {
        _assetDependencies[assetName] = dependencies;
    }
}

prop.objectReferenceValueでObjectを取得できるため何をドラッグアンドドロップで入れたのか取得できています。Prefabであろうが、マテリアルであろうがあとはAssetDatabase.GetDependencies(assetPath, true)を行えばUnityの機能でアセット参照を全部出してくれます。
今回はアセット参照が知りたいため、Where(dependency => !dependency.EndsWith(".cs"))でC#スクリプトは除外します。
最終的にPrefab名+かかわるアセット参照の関係でList表示したいのでDictionary<string, List<string>>を作成して入れます。Keyにはアセット名、Valueには参照関係のListを入れます。
このDictionaryを使用してEditor拡張で表示をすると
image.png
このように表示さて、SubTrackのClipに入っているアセットから参照情報を取得できました。

終わりに

このツールを作成していて最初はAssetDatabase.GetDependenciesを使用しただけで終わろうと思っていましたがどのアセットに問題があるのか全くわからなかったのでPrefabやアセットどこにわかる表示を行えるようにしました。
GUIDから関わるアセットを全表示する方法が多分あるのですが、これはおそらくアセット全検索になり速度が出るのか怪しかったためこの方法に行きつきました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?