[Unity] AssetDatabase.FindAssets 自動載入所有指定類型資產物件語法

發表日期:
2022.05.25
/
分類:
平常我們是用手動拖拉的方式在 Inspector 中設定腳本所需的預製物件,當資料量一多時,手動操作會拖慢開發進度,所以這部分應該要設計成自動化的機制。 AssetDatabase 這個類

平常我們是用手動拖拉的方式在 Inspector 中設定腳本所需的預製物件,當資料量一多時,手動操作會拖慢開發進度,所以這部分應該要設計成自動化的機制。

AssetDatabase 這個類別依賴在 UnityEditor 命名空間下,意味著這個方法只能在編輯器環境下運作,不可部署到正式執行環境中,所以我們不能用這篇說明的手法來達到 Asset 資源的動態載入 (請左轉 Addressable)。

在這篇文章中,我們將會使用到 AssetDatabase 類別下的 FindAssets、LoadAssetAtPath、GUIDToAssetPath 三個方法,並搭配 System.Linq 語法完成自動化功能。

AssetDatabase.FindAssets

FindAssets 顧名思義就是搜尋專案資產,也就是 Assets 資料夾內的所有東西。他需要輸入的參數為字串,我們可以直接在 Project 視窗中測試搜尋字串的語法:

字串中的 t 代表 Type,假設我們要搜尋的 Prefab 或 ScriptableObject 中帶有 ItemData 類別,可以輸入:

string[] itemGUIDs = AssetDatabase.FindAssets($"t:{nameof(ItemData)}");

如果 FindAssets 有找到物件,將會以字串陣列方式回傳物件的 GUID。

AssetDatabase.LoadAssetAtPath

LoadAssetAtPath 就更簡單了,只要在輸入的參數中給予正確的路徑,此方法將會回傳目標物件給你。

例如:

ItemData item = AssetDatabase.LoadAssetAtPath<ItemData>("Assets/Settings/Item Data 1.asset");

AssetDatabase.GUIDToAssetPath

GUIDToAssetPath 函式是一個轉換器,可以將輸入的 GUID 字串轉為物件的路徑字串,這是我們用來完成這個自動化機制的重要核心。

自動化載入語法

一開始我們需要使用 #if 語法來確保其中的程式碼只會在編輯器環境下運作,所以要分別將 using UnityEditor 與 OnValidate 用 #if UNITY_EDITOR 包起來。

接下來將按照以下流程完成物件搜尋作業:

  1. 在 OnValidate 中透過 FindAssets 找到物件的 GUID。
  2. 透過 Linq 的 Select 將 GUID 提取出來。
  3. 透過 GUIDToAssetPath 將物件 GUID 轉換為路徑。
  4. 透過 LoadAssetAtPath 將物件路徑轉為物件本身。
  5. 使用 ToArray 將所有結果轉為物件陣列。
using UnityEngine;
using System.Linq;

#if UNITY_EDITOR
using UnityEditor;
#endif

public class GameManager : MonoBehaviour
{
    public ItemData[] items;

#if UNITY_EDITOR
    private void OnValidate()
    {
        items =
            AssetDatabase.FindAssets($"t:{nameof(ItemData)}")
                         .Select(x => AssetDatabase.LoadAssetAtPath<ItemData>(AssetDatabase.GUIDToAssetPath(x)))
                         .ToArray();
    }
#endif
}

雖然這串語法又臭又長,但其實你可以將它變成一個泛型的方法,也可以用靜態類別的方式以便未來使用:

using UnityEngine;
using System.Linq;

#if UNITY_EDITOR
using UnityEditor;
#endif

public static class AssetExtension
{
    public static T[] FindAllAssets<T>() where T : Object
    {
        return AssetDatabase.FindAssets($"t:{typeof(T).Name}")
                            .Select(x => AssetDatabase.LoadAssetAtPath<T>(AssetDatabase.GUIDToAssetPath(x)))
                            .ToArray();
    }
}

只要呼叫 AssetExtension.FindAllAssets 方法即可搜尋物件:

#if UNITY_EDITOR
    private void OnValidate()
    {
        items = AssetExtension.FindAllAssets<ItemData>();
    }
#endif

Inspector 結果:


將這些可以加速開發的語法好好記錄起來,當未來需要用到相同功能時就可以直接派上用場。

comments powered by Disqus