1. 程式人生 > >Unity 3D 資源的載入與釋放

Unity 3D 資源的載入與釋放

版本:unity 5.4.1  語言:C#

海水先在這裡坑一會,看了裡面的演算法深深感到自己數學能力的不足,經過同學的推薦,我準備先看會《數值分析》閉關修煉一下。

至於我在看的實戰核心技術的第十章MVC設計框架,提供了一堆無用的程式碼,然後讓你去看他的課程,我就自己研究一下如何從Asset中載入到場景中,又如何在場景中釋放資源。

總結一下網上一共有三種方法(這次最終解決了AssetBundle的載入問題,AssetBundle原來是要打包後才能載入……):靜態載入、Resources.Load、AssetBundle.LoadAsset。

各有不同的用處吧,本地的話前兩個更加容易管理使用,

AssetBundle可以用在網路環境下。

接下來看程式碼:

(參考:http://www.taidous.com/portal.php?mod=view&aid=445&page=1)

public class ResManager : MonoBehaviour {

    public GameObject tps;

	void Start ()
    {
        //StartCoroutine(LoadResByResources("TPS"));
        //StartCoroutine(LoadResByStatic());
        StartCoroutine(LoadResByBundle("file://" + Application.dataPath + @"/Resources/rs.assetbundle", "assets/standard assets/characters/thirdpersoncharacter/prefabs/thirdpersoncontroller.prefab"));
    }

    // Resources的方法載入資源,只能在Resources資料夾下讀取,不想建立Resources資料夾的可以考慮靜態載入
    IEnumerator LoadResByResources(string path)
    {
        Resources.UnloadUnusedAssets();

        // 讀取,此時僅讀取了資源的少量資訊,並不佔多少記憶體
        GameObject go = Resources.Load<GameObject>(path);

        yield return new WaitForSeconds(5f);

        // 建立,如果Instantiate過多會產生卡頓,所以在載入大量資源的時候,考慮物件池
        // 先在讀取進度的時候把物件創建出來,並SetActive(false),使用的時候SetActive(true)
        GameObject goInit = Instantiate(go);
        goInit.transform.parent = transform;
        goInit.transform.localPosition = Vector3.zero;
        goInit.transform.localRotation = Quaternion.identity;

        yield return new WaitForSeconds(5f);

        // 銷燬物件,但各種資源還佔據記憶體
        Destroy(goInit);

        yield return new WaitForSeconds(5f);

        // 解除安裝所有沒有引用的資源,相當於清空了記憶體
        // 但最好不要主動使用,轉換場景的時候會清空資源
        Resources.UnloadUnusedAssets();
    }

    // 靜態的方法載入資源,效果與Resources載入類似
    IEnumerator LoadResByStatic()
    {
        Resources.UnloadUnusedAssets();

        yield return new WaitForSeconds(5f);

        GameObject goInit = Instantiate(tps);
        goInit.transform.parent = transform;
        goInit.transform.localPosition = Vector3.zero;
        goInit.transform.localRotation = Quaternion.identity;

        yield return new WaitForSeconds(5f);
        Destroy(goInit);

        yield return new WaitForSeconds(5f);
        Resources.UnloadUnusedAssets();
    }

    // 使用AssetBundle載入資源,在LoadAsset的時候就會載入大量的資源
    // 所以例項化時載入的資源量反而小,可以考慮利用這種方法做載入而不卡頓
    IEnumerator LoadResByBundle(string path, string name)
    {
        Resources.UnloadUnusedAssets();

        // 建立WWW讀取,這邊是本地
        WWW bundle = new WWW(path);
        yield return bundle;

        yield return new WaitForSeconds(5f);

        // 從讀取到的資源中獲取對應prefab
        //Object obj = bundle.assetBundle.Load(name);   //方法已經被廢棄
        Object obj = bundle.assetBundle.LoadAsset(name);

        yield return new WaitForSeconds(5f);

        // 例項化
        GameObject goInit = Instantiate(obj) as GameObject;
        goInit.transform.parent = transform;
        goInit.transform.localPosition = Vector3.zero;
        goInit.transform.localRotation = Quaternion.identity;

        yield return new WaitForSeconds(5f);

        // 刪除
        Destroy(goInit);

        yield return new WaitForSeconds(5f);

        // Unload釋放記憶體映象,引數是是否強制刪除記憶體資源
        // true強制刪除,即使記憶體有引用也刪除
        //bundle.assetBundle.Unload(true);

        // 刪除沒有引用的資源,比如說這邊,如果呼叫的是這個方法的的話
        // 雖然資源已經被刪除了,但記憶體中還保留的該prefab,直到呼叫Resources.UnloadUnusedAssets()
        bundle.assetBundle.Unload(false);

        Resources.UnloadUnusedAssets();
    }

    // 打包方法是jiange啊啊啊撰寫的(http://blog.csdn.net/janeky/article/details/17652021)
    // 這個方法是打包當前專案的資源,從而形成assetbundle檔案,供LoadResByBundle載入
    [MenuItem("Assets/Build AssetBundle From Selection")]
    static void ExportResourceRGB2()
    {
        // 開啟儲存面板,獲得使用者選擇的路徑  
        string path = EditorUtility.SaveFilePanel("Save Resource", "", "New Resource", "assetbundle");

        if (path.Length != 0)
        {
            // 選擇的要儲存的物件
            Object[] selection = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
            //打包  
            BuildPipeline.BuildAssetBundle(Selection.activeObject, selection, path, BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets, BuildTarget.StandaloneWindows);
        }
    }
}

靜態讀取和Resources.Load最好先把要用到的例項出來,嗯,在進度讀取的時候做,然後SetActive(false)將其隱藏,這樣卡頓現象應該不會出現吧。

好了,這本書我看了,再寫個熱更新吧,其他章節也沒什麼好看的了。