什么是資源(Asset)
http://blog.csdn.net/u014230923/article/details/51433455
Unity常用的資源大概有3類:
- 純資源(material,texture,shader,audio ……)這些資源不能直接拖到場景里使用。
- 預置(prefab),這種資源需要實例化instantiate之后才能使用
- scene也是一種資源
還有一些平時不太關(guān)注的:腳本對象,文本文件,unity自己內(nèi)置的資源(像新建粒子時的默認材質(zhì)之類的),這些也是資源。
資源管理
http://blog.csdn.net/qq_18995513/article/details/51955609
Unity的資源管理模式,包括在編輯器管理(使用AssetDatabase)和在運行時管理(使用Resources和AssetBundle)。
1. 編輯器管理: AssetDatabase
在編輯器內(nèi)加載卸載資源,并不能在游戲發(fā)布時使用,它只能在編輯器內(nèi)使用。但是,它加載速度快,效率高,適合在測試時使用。
因為只能在編輯器使用,要加個宏防止報錯:
#if UNITY_EDITOR
using UnityEditor;
#endif
加載(Load) Asset
#if UNITY_EDITOR
assetInfo.asset = UnityEditor.AssetDatabase.LoadAssetAtPath(BundleUtils.RealPath(assetPath), type);
assetInfo.assetName = assetPath;
assetInfo.type = type;
assets[assetPath] = assetInfo;
#else
卸載(Unload) Asset
https://docs.unity3d.com/ScriptReference/Resources.UnloadAsset.html
Resources.UnloadAsset(asset);
Unloads assetToUnload from memory.
This function can only be called on Assets that are stored on disk.
If there are any references from game objects in the scene to the asset and it is being used then Unity will reload the asset from disk as soon as it is accessed.
需要注意的是,調(diào)用Resources.UnloadAsset()來清理資源時,只是標記該資源需要被GC回收,但不是立刻就被回收的。需要調(diào)用
System.GC.Collect();
使用腳本創(chuàng)建Asset
// 創(chuàng)建資源
public class TestCreateAsset : MonoBehaviour {
void Start () {
#if UNITY_EDITOR
// 加載資源
Material mat = AssetDatabase.LoadAssetAtPath("Assets/Materials/New Material.mat", typeof(Material)) as Material;
// 以mat為模板創(chuàng)建mat2
Material mat2 = Object.Instantiate<Material>(mat);
// 創(chuàng)建資源
AssetDatabase.CreateAsset(mat2, "Assets/Materials/1.mat");
// 刷新編輯器,使剛創(chuàng)建的資源立刻被導入,才能接下來立刻使用上該資源
AssetDatabase.Refresh();
// 使用資源
Debug.Log(mat2.name);
#endif
}
}
運行腳本后,會發(fā)現(xiàn)在編輯器里就會出現(xiàn):Project視窗中多了一個剛創(chuàng)建的1.mat資源。
修改Asset
具體見上面鏈接
2. 在運行時管理:使用Resources[1]
Resources.Load就是從一個缺省打進程序包里的AssetBundle里加載資源,而一般AssetBundle文件需要你自己創(chuàng)建,運行時 動態(tài)加載,可以指定路徑和來源的。
3. 在運行時管理:使用AssetBundle[2]

注意下圖有一些錯誤需要更新:
- 這張圖中的
CreateFromFile函數(shù)在5.6.0中被去掉了,LoadFromFile是一樣的 - AssetBundle并不一定是整個被解壓縮到內(nèi)存里,根據(jù)Unity官方文檔解釋,只有LZMA格式壓縮的AssetBundle會被解壓到內(nèi)存,而未壓縮/LZ4壓縮的Assetbundle是直接從磁盤讀取的。
The function supports bundles of any compression type. In case of lzma compression, the data will be decompressed to the memory. Uncompressed and chunk-compressed bundles can be read directly from disk. [3]
各種加載和初始化:
AssetBundle.LoadFromFile
創(chuàng)建一個AssetBundle內(nèi)存鏡像。注意同一個assetBundle文件在沒有Unload之前不能再次被使用WWW.AssetBundle
同上。當然要先new一個再 yield return 然后才能使用AssetBundle.Load(name)
從AssetBundle讀取一個指定名稱的Asset并生成Asset內(nèi)存對象。如果多次Load同名對象,除第一次外都只會返回已經(jīng)生成的Asset對象,也就是說多次Load一個Asset并不會生成多個副本(singleton)Resources.Load(string path, Type systemTypeInstance)
同上。只是Resources文件夾加載. e.g.rend.material.mainTexture = Resources.Load("glass") as Texture;-
一個比較特殊的AssetBundle: 生成AssetBundle的時候會生成一些Manifest,根目錄下還會有一個與根目錄同名的AssetBundle以及Manifest文件,通過運行時加載這個AssetBundle,可以得到一個AssetBundleManifest對象,然后就可以通過這個對象得到AssetBundle直接的依賴關(guān)系。
-
AssetBundleManifest存儲的是依賴文件列表。我們得知道AssetBundle們在哪兒,所以獲得根目錄下根目錄同名的AssetBundleManifest是將其它AssetBundle從硬盤load到內(nèi)存的第一步。具體可以進行如下操作 -
AssetBundle manifestBundle = AssetBundle.CreateFromFile(Application.dataPath +"/ab/Assetbundle");
AssetBundleManifest manifest = manifestBundle.LoadAsset("AssetBundleManifest") as AssetBundleManifest; -
string[] bundleList = bundleManifest.GetAllAssetBundles();可以獲得所有bundle -
string[] dependFiles = bundleManifest.GetAllDependencies(bundleName);可以獲得依賴文件列表
-
-
Instantiate(Object original)注意: texture之類的是不用instantiate的,只要把需要貼圖的位置指向它就可以了, e.g.
obj1.renderer.material.mainTexture = AssetBundle1.Load("wall") as Texture;對于prefab,只有實例化才能使用。因此需要將從AssetBundle load出來的Prefab進行instantiate才能使用。
所有prefab實例都是prefab的克隆,所以運行時生成對象會有Clone標記。
-
這個函數(shù)的clone的是這個object的完整結(jié)構(gòu),包括其所有Component和子物體(詳見以下附的官方文檔),淺Copy,并不復制所有引用類型。
When you call Instantiate() on anything that exists in a Scene, such as a Prefab or a GameObject, Unity serializes the object. This happens both at runtime and in the Editor. Note that everything that derives from UnityEngine.Object can be serialized.
Unity then creates a new GameObject and deserializes (that is, loads) the data onto the new GameObject. Next, Unity runs the same serialization code in a different variant to report which other UnityEngine.Objects are being referenced. It checks all referenced UnityEngine.Objects to see if they are part of the data being Instantiated(). If the reference points to something “external”, such as a Texture, Unity keeps that reference as it is. If the reference points to something “internal”, such as a child GameObject, Unity patches the reference to the corresponding copy.
各種釋放
-
釋放對象
- 自動釋放:
- 在進入新場景(scene/level)的時候會自動銷毀所有場景內(nèi)對象,然后加載新場景里的對象[5]。
- 但是,可以通過
DontDestroyOnLoad(object)使得某個對象不被自動銷毀。如果這個對象是component或者game object,那么它的整個transform hierarchy都不會被銷毀。
- 手動釋放:
-
Destroy()[6]可用于銷毀gameobject, component或asset。銷毀object會把整個gameobject銷毀,包括它的所有component和transform children。銷毀component會把這個component從gameobject上去掉(所以,此時component沒有從內(nèi)存中去掉,不過如果沒有任何引用關(guān)系了,可以通過下面提到的Resources.UnloadUnusedAssets()釋放)。 -
Destroy()后內(nèi)存的回收會delay到當前update結(jié)束后執(zhí)行。如果要立即執(zhí)行,需要使用GC.Collect()強制垃圾收集器立即釋放內(nèi)存 -
Destroy()如果用于銷毀從文件加載的Asset對象會銷毀相應(yīng)的資源文件!但是如果銷毀的Asset是Copy的或者用腳本動態(tài)生成的,只會銷毀內(nèi)存對象。[2] -
Resources.UnloadAsset(Object): 顯式的釋放已加載的Asset對象,只能卸載磁盤文件加載的Asset對象 -
Resources.UnloadUnusedAssets(): 用于釋放所有沒有引用的Asset對象
-
- 自動釋放:
-
釋放AssetBundle
-
AssetBundle.Unload(false): 釋放AssetBundle文件內(nèi)存鏡像 -
AssetBundle.Unload(true): 釋放AssetBundle文件內(nèi)存鏡像同時銷毀所有已經(jīng)Load的Assets內(nèi)存對象
-
-
Unity官方文檔
Resources: https://docs.unity3d.com/540/Documentation/ScriptReference/Resources.html ? -
Reference: http://www.cnblogs.com/88999660/archive/2013/03/15/2961663.html ? ?
-
https://docs.unity3d.com/ScriptReference/AssetBundle.LoadFromFile.html ?
-
Unity官方文檔
Object.DontDestroyOnLoad: https://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html ? -
Unity官方文檔
Destroy: https://docs.unity3d.com/ScriptReference/Object.Destroy.html ?