1、Assets(在编辑器环境加载)
2、Resources(游戏运行时加载)
3、AssetsBundle(在线更新)
Assets(在编辑器环境加载)
UnityEditor.AssetDatabase.LoadAssetAtPath
Editor下的加载方式,加载路径是项目下的路径,除了Resources文件夹都不会随着打包打到游戏本体内。
注意路径是带Assets开头,并且需要后缀
Texture2D t = AssetDatabase.LoadAssetAtPath("Assets/UI/cube.png", typeof(Texture2D)) as Texture2D;
但AssetDataBase不支持异步,所以editor下的效果和打包效果不一样,而且这样的加载还需要后缀,或者用ab名去索引,否则导致会多些一些代码,不过问题不大,习惯就好。
如果DestroyImmediately(true)后除非重启unity,再也加载不出来
Resources
- Resources类只能读取名为“Resources”的文件夹里的资源,注意是复数形式。
- Resources文件夹需要用户自己新建,建议创建并放在Asset文件夹的根目录下。
- Unity打包发布时,Resources文件夹里的资源在会被打入包中。
- Resources类加载资源时,使用”Resources”文件夹开始的相对路径,且不包含资源的扩展名。如要加载Asset/Resources/Images/1.jpg资源,加载路径应该写”Images/1”。
using UnityEngine;
using System.Collections;
public class TestResources : MonoBehaviour {
void Start () {
/*
加载资源
*/
// 预制体返回GameObject类型,路径不包含拓展名
GameObject go = Resources.Load<GameObject>("Prefabs/Cube");
// 资源在加载后要被实例化才能看到(等于克隆一个出来)
GameObject go2 = Instantiate(go);
// 加载其他非GameObject类型的资源
Texture2D image = Resources.Load<Texture2D>("Images/1");
// 测试是否加载成功
Debug.Log(image.name);
/*
卸载资源
*/
// 卸载非GameObject类型的资源,会将已加载资源及其克隆体剔除
Resources.UnloadAsset(image);
// 卸载GameObject类型的资源的克隆体
Destroy(go2);
#if UNITY_EDITOR
// 在编辑器模式下无法卸载go物体,否则会报错让改用DestroyImmediate(obj, true),但这样做会连文件夹里的原始Asset一并删除!
#else
DestroyImmediate(go); // 所有该物体的克隆体也都一并被删除,即本例中的go2物体
#endif
}
}
总结一下:
- Resources类的资源加载方式只有一种,但卸载方式却有三种,加载容易卸载难。选择有误会报错,甚至会连文件夹里的原始Asset一并删除!
- Resources.UnloadAsset(obj):卸载非 GameObject类型的资源,会将内存中已加载资源及其克隆体卸载。
- Destroy(obj):仅用于卸载GameObject类型的资源的克隆体。
- DestroyImmediately(obj):卸载GameObject类型的资源,会将内存中已加载资源及其克隆体卸载,但该方法只能用在非编辑模式下,否则会报错提示改为DestroyImmediately(obj, true),然而编辑模式下使用该函数会连文件夹里的原始Asset一并删除。
官方推荐的卸载资源方法是:
public static AsyncOperation UnloadUnusedAssets()//Resources.UnloadUnusedAssets()
从返回值可以看出这是个异步操作,即Unity需要花费一定时间去检索哪些资源没有被使用才会去卸载。使用方便,但不快捷,还要注意哪些资源是否一直被全局变量引用,导致一直无法释放。
AssetsBundle
1、制作AssetBundle
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
public class BuildAssetsBundle{
[MenuItem("Publish/Build Bundle")] // 在编辑器上创建打包菜单,BuildBundle为菜单的响应函数
public static void BuildBundle()
{
// 1、生成AssetBundleBuild数组
List<AssetBundleBuild> builds = new List<AssetBundleBuild>();
AssetBundleBuild b = new AssetBundleBuild();
b.assetBundleName = "1.unity3d"; // 打包之后的包体名
b.assetNames = new string[] { "Assets/Resources/Prefabs/BackpackPanel.prefab" }; // 打包的资源路径,可将多个资源打包进一个包体
builds.Add(b);
// 2、打包
// BuildAssetBundles(输出路径,需要打包的AssetBundleBuild数组,打包方式,平台)
// 打包方式CollectDependencies:对于一个prefab,将其依赖的资源都打包进去。如prefab有个动画控制器组件,它引用的动画控制器也会打包进去
// 平台:如果是StandaloneWindows64,则打包出来的资源只能在Windows64位平台上加载
BuildPipeline.BuildAssetBundles("Assets/Bundle", builds.ToArray(), BuildAssetBundleOptions.CollectDependencies, BuildTarget.StandaloneWindows64);
}
}
2、从AssetBundle加载资源
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class LoadAssetBundle : MonoBehaviour {
// Use this for initialization
void Start () {
StartCoroutine(Load());
}
IEnumerator Load()
{
// 1、使用www加载AssetBundle
//WWW www = new WWW("http://.../1.unity3d"); // 从网上加载
//WWW www = new WWW("file://" + Application.streamingAssetsPath + "1.unity3d"); // 从手机上加载,需要在Assets下创建Streaming Assets文件夹,Streaming Assets与Resources两个文件夹都会打包到包体中
WWW www = new WWW(@"file:///F:\UnityProject\Backpack\Assets\Bundle\1.unity3d"); // Windows上从本地加载
yield return www;
// 2、从AssetBundle中加载asset
AssetBundle bundle = www.assetBundle;
// 异步加载,分帧,慢点,但不会卡住主线程。参数一为资源路径,参数二为资源类型。参数一的资源路径和资源打包前的路径是一样的
AssetBundleRequest request = bundle.LoadAssetAsync("Assets/Resources/Prefabs/BackpackPanel.prefab", typeof(GameObject));
yield return request;
GameObject go = request.asset as GameObject;
// 同步加载,不分帧,较快,但资源大就会卡住主线程。
//GameObject go = bundle.LoadAsset<GameObject>("Assets/Resources/Prefabs/BackpackPanel.prefab");
Instantiate(go);
www.Dispose(); // 释放www
//bundle.Unload(true); // 完全卸载bundle
//bundle.Unload(false); // 部分卸载bundle,正在被使用的不卸载
//Resources.UnloadUnusedAssets(); // 当不再被使用后,用这个函数来卸载
}
}