目录为:Assets/Scripts/ResourceManager/
ResourcesManager.cs
具体怎么用,下一篇详细写写吧。
ResourceManager.cs
using System;
using System.IO;
using System.Xml;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Object = UnityEngine.Object;
//---------------------------------------------------------------
//这个ResourcesManager非常重要 |
//---------------------------------------------------------------
//Resources Manager
//继承Unity单例
//这种一般是添加到GameObject上成为一个component
public class ResourcesManager: UnitySingleton<ResourcesManager>
{
//是否通过assetbundle加载资源
public bool UsedAssetBundle = false;
//是否已经初始化
private bool mInit = false;
//帧数
private int mFrameCount = 0;
//当前的请求
private Request mCurrentRequest = null;
//请求队列
private Queue<Request> mAllRequests = new Queue<Request>();
//保存读取的Resource信息
private AssetInfoManager mAssetInfoManager = null;
private Dictionary<string, string> mResources = new Dictionary<string, string>();
//加载的资源信息
private Dictionary<string, ResourceUnit> mLoadedResourceUnit = new Dictionary<string, ResourceUnit>();
public delegate void HandleFinishLoad(ResourceUnit resource);
public delegate void HandleFinishLoadLevel();
public delegate void HandleFinishUnLoadLevel();
//初始化
//在这里面先读取AssetInfo.bytes和Resource.bytes两个文件
public void Init()
{
//使用assetbundle打包功能
if (UsedAssetBundle)
{
//AssetInfo.bytes
mAssetInfoManager = new AssetInfoManager ();
mAssetInfoManager.LoadAssetInfo ();
//Resources.bytes
ArchiveManager.Instance.Init ();
}
mInit = true;
}
//Update函数
public void Update()
{
//检查是否Init过
if (!mInit)
{
return;
}
//当前Request已处理完,但请求队列中还有请求
if (null == mCurrentRequest && mAllRequests.Count > 0)
{
handleRequest ();
}
++mFrameCount;
if (mFrameCount == 300)
{
//Resources.UnloadUnusedAssets();
mFrameCount = 0;
}
}
//主要函数
//处理资源相关请求
private void handleRequest()
{
//使用assetbundle打包功能
if (UsedAssetBundle)
{
//获取当前的请求
mCurrentRequest = mAllRequests.Dequeue ();
//相对Asset的完整资源路径
string fileName = mCurrentRequest.mFileName;
//这里是 RequestType
switch (mCurrentRequest.mRequestType)
{
//这个分支里面只检查是否加载过资源,而并不负责加载资源
case RequestType.LOAD:
{
//这里是 ResourceType
switch (mCurrentRequest.mResourceType)
{
//资源为ASSET和PREFAB时
case ResourceType.ASSET:
case ResourceType.PREFAB:
{
if (mLoadedResourceUnit.ContainsKey (fileName))
{
//已经加载过了,所以completed
mCurrentRequest.mResourceAsyncOperation.mComplete = true;
mCurrentRequest.mResourceAsyncOperation.mResource = mLoadedResourceUnit [fileName] as ResourceUnit;
if (null != mCurrentRequest.mHandle)
{
mCurrentRequest.mHandle (mLoadedResourceUnit [fileName] as ResourceUnit);
}
handleResponse ();
}
//没加载过
else
{
//传入相对路径名称
//StartCoroutine(_load(fileName, mCurrentRequest.mHandle, mCurrentRequest.mResourceType, mCurrentRequest.mResourceAsyncOperation));
//啥也没做
}
}
break;
//-------------------------------
case ResourceType.LEVELASSET:
{
Debug.LogError ("do real need a single level asset??? this is have not decide!!!", ResourceCommon.DEBUGTYPENAME);
}
break;
//--------------------------------
case ResourceType.LEVEL:
{
Debug.LogError ("this is impossible!!!", ResourceCommon.DEBUGTYPENAME);
}
break;
}
}
break;
//卸载资源
case RequestType.UNLOAD:
{
if (!mLoadedResourceUnit.ContainsKey (fileName))
{
Debug.LogError ("can not find " + fileName);
}
else
{
//(mLoadedResourceUnit[fileName] as ResourceUnit).reduceReferenceCount();
}
handleResponse ();
}
break;
//加载场景
case RequestType.LOADLEVEL:
{
//加载场景,会先加载场景所用到的所以依赖资源,再异步加载场景
StartCoroutine (_loadLevel (fileName, mCurrentRequest.mHandleLevel, ResourceType.LEVEL, mCurrentRequest.mResourceAsyncOperation));
}
break;
//卸载场景
case RequestType.UNLOADLEVEL:
{
if (!mLoadedResourceUnit.ContainsKey (fileName))
{
Debug.LogError ("can not find level" + fileName, ResourceCommon.DEBUGTYPENAME);
}
else
{
//(mLoadedResourceUnit[fileName] as ResourceUnit).reduceReferenceCount();
if (null != mCurrentRequest.mHandleUnloadLevel)
{
mCurrentRequest.mHandleUnloadLevel ();
}
}
handleResponse ();
}
break;
}
}
//不使用AssetBundle打包
//这个分支其实几乎就没什么用,因为一般是会用AssetBundle打包
else
{
//获取Request
mCurrentRequest = mAllRequests.Dequeue ();
switch (mCurrentRequest.mRequestType)
{
case RequestType.LOAD:
{
switch (mCurrentRequest.mResourceType)
{
case ResourceType.ASSET:
case ResourceType.PREFAB:
{
//暂时不处理,直接使用资源相对路径
//StartCoroutine(_load(mCurrentRequest.mFileName, mCurrentRequest.mHandle, mCurrentRequest.mResourceType, mCurrentRequest.mResourceAsyncOperation));
}
break;
//-----------------------------------
case ResourceType.LEVELASSET:
{
Debug.LogError ("do you real need a single level asset??? this is have not decide!!!", ResourceCommon.DEBUGTYPENAME);
}
break;
//-----------------------------------
case ResourceType.LEVEL:
{
Debug.LogError ("this is impossible!!!", ResourceCommon.DEBUGTYPENAME);
}
break;
}
}
break;
case RequestType.UNLOAD:
{
handleResponse ();
}
break;
case RequestType.LOADLEVEL:
{
StartCoroutine (_loadLevel (mCurrentRequest.mFileName, mCurrentRequest.mHandleLevel, ResourceType.LEVEL, mCurrentRequest.mResourceAsyncOperation));
}
break;
case RequestType.UNLOADLEVEL:
{
if (null != mCurrentRequest.mHandleUnloadLevel)
{
mCurrentRequest.mHandleUnloadLevel ();
}
handleResponse ();
}
break;
}
}
}
//表示当前Request已经完成
private void handleResponse()
{
mCurrentRequest = null;
}
//传入Resources下相对路径名称 例如:Resources/Game/Effect1 传入GameEffect1
public ResourceUnit loadImmediate(string filePathName, ResourceType resourceType, string archiveName = "Resources")
{
//使用assetbundle打包
if (UsedAssetBundle)
{
//添加Resource
string completePath = "Resources/" + filePathName;
string completeName = ArchiveManager.Instance.GetPath ("Resources", completePath);
//根据场景名称获取asset信息
AssetInfo sceneAssetInfo = mAssetInfoManager.GetAssetInfo (completeName);
//获取依赖的asset索引
foreach(int index in sceneAssetInfo.mDependencies)
{
//根据索引获取依赖的Asset
AssetInfo depencyAsset = mAssetInfoManager.GetAssetInfo (index);
string depencyAssetName = depencyAsset.mName;
//加载asset
_LoadImmediate (depencyAssetName, ResourceType.ASSET);
}
//加载自己本身
ResourceUnit unit = _LoadImmediate (completeName, resourceType);
return unit;
}
//不使用assetbundle
else
{
Object asset = Resources.Load (filePathName);
ResourceUnit resource = new ResourceUnit (null, 0, asset, null, resourceType);
return resource;
}
}
//-------------------------------------------------------------------
//这个函数是主要的函数,
//调用这个函数,然后会将加载scene的Request加入RequestQueue,
//然后在ResourcesManager的Update函数中会处理这个Request,真正地加载Scene
//-------------------------------------------------------------------
public ResourceAsyncOperation loadLevel(string fileName, HandleFinishLoadLevel handle, string archiveName = "Level")
{
//使用assetbundle打包
if (UsedAssetBundle)
{
//ResourceCommon.Log("loadLevel : " + fileName + " and the archiveName is : " + archiveName);
//获取完整路径
string completeName = ArchiveManager.Instance.GetPath(archiveName, fileName);
if (mLoadedResourceUnit.ContainsKey(completeName))
{
Debug.LogError ("why you load same level twice, maybe you have not unload last time!!!", ResourceCommon.DEBUGTYPENAME);
return null;
}
else
{
ResourceAsyncOperation operation = new ResourceAsyncOperation (RequestType.LOADLEVEL);
mAllRequests.Enqueue (new Request (completeName, ResourceType.LEVEL, handle, RequestType.LOADLEVEL, operation));
return operation;
}
}
//不使用assetbundle
else
{
ResourceAsyncOperation operation = new ResourceAsyncOperation (RequestType.LOADLEVEL);
mAllRequests.Enqueue (new Request (fileName, ResourceType.LEVEL, handle, RequestType.LOADLEVEL, operation));
return operation;
}
}
//path:相对Assets的完整资源路径
//加载一个level,然后也把所有dependencies都加载了
//先加载场景依赖的所有资源,再加载场景本身
private IEnumerator _loadLevel(string path, HandleFinishLoadLevel handle, ResourceType resourceType, ResourceAsyncOperation operation)
{
//使用assetbundle打包
if (UsedAssetBundle)
{
//根据场景名称获取asset信息
AssetInfo sceneAssetInfo = mAssetInfoManager.GetAssetInfo (path);
//获取该包总大小
operation.mAllDependenciesAssetSize = mAssetInfoManager.GetAllAssetSize (sceneAssetInfo);
//获取依赖的asset的索引
foreach (int index in sceneAssetInfo.mDependencies)
{
//根据索引获取依赖的asset
AssetInfo depencyAsset = mAssetInfoManager.GetAssetInfo (index);
string depencyAssetName = depencyAsset.mName;
//加载场景依赖assetbundle
//每一个AssetBundle文件都应当有一个ResourceUnit,这里加载了然后mLoadedResourceUnit
ResourceUnit unit = _LoadImmediate (depencyAssetName, ResourceType.LEVEL);
operation.mLoadDependenciesAssetSize += unit.AssetBundleSize;
}
//加载场景
int sceneAssetBundleSize = 0;
//加载其他那些小资源也是这么加载的
byte[] binary = ResourceCommon.getAssetBundleFileBytes (path, ref sceneAssetBundleSize);
AssetBundle assetBundle = AssetBundle.CreateFromMemoryImmediate (binary);
if (!assetBundle)
{
Debug.LogError ("Create scene assetbundle " + path + "in _LoadImmediate failed");
}
//添加场景大小
operation.mLoadDependenciesAssetSize += sceneAssetBundleSize;
//path:相对Assets的完整路径
//这里异步加载场景Level
AsyncOperation asyncOperation = Application.LoadLevelAsync (ResourceCommon.getFileName (path, false));
operation.asyncOperation = asyncOperation;
yield return asyncOperation;
handleResponse ();
operation.asyncOperation = null;
operation.mComplete = true;
operation.mResource = null;
if (null != handle)
{
handle ();
}
}
//不使用assetbundle
else
{
ResourceUnit level = new ResourceUnit (null, 0, null, path, resourceType);
//获取加载场景名称
string sceneName = ResourceCommon.getFileName (path, true);
AsyncOperation asyncOperation = Application.LoadLevelAsync (sceneName);
operation.asyncOperation = asyncOperation;
yield return asyncOperation;
handleResponse ();
operation.asyncOperation = null;
operation.mComplete = true;
if (null != handle)
{
handle ();
}
}
}
//单个资源加载
ResourceUnit _LoadImmediate(string fileName, ResourceType resourceType)
{
//没有该资源,加载
if (!mLoadedResourceUnit.ContainsKey(fileName))
{
//资源大小
int assetBundleSize = 0;
//加载Assetbundle文件,获取bytes
byte[] binary = ResourceCommon.getAssetBundleFileBytes (fileName, ref assetBundleSize);
//bytes加载成AssetBundle
AssetBundle assetBundle = AssetBundle.CreateFromMemoryImmediate (binary);
if (!assetBundle)
{
Debug.LogError ("create assetbundle " + fileName + " in _LoadImmediate failed");
}
Object asset = assetBundle.Load (fileName);
if (!asset)
{
Debug.LogError ("load assetbundle " + fileName + "in _LoadImmediate failed");
}
ResourceUnit ru = new ResourceUnit (assetBundle, assetBundleSize, asset, fileName, resourceType);
//添加到资源中
mLoadedResourceUnit.Add (fileName, ru);
return ru;
}
else
{
return mLoadedResourceUnit [fileName];
}
}
//这个目录是当前运行环境的沙箱目录的相对目录
public static Stream Open(string path)
{
string localPath;
//Android跟IOS环境使用沙箱目录
if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer)
{
//啥项目录 + "path" + ".bytes"
localPath = string.Format ("{0}/{1}", Application.persistentDataPath, path + ResourceCommon.assetbundleFileSuffix);
}
//Windows下使用assetbundle资源目录
else
{
//Application.dataPath + "/assetbundles/" + "path" + ".bytes"
localPath = ResourceCommon.assetbundleFilePath + path + ResourceCommon.assetbundleFileSuffix;
}
//首先检查沙箱中是否有更新资源
if (File.Exists(localPath))
{
return File.Open (localPath, FileMode.Open, FileAccess.Read, FileShare.Read);
}
//没有的话原始包中查找
else
{
//Resources.Load的相对目录是:Resources目录下
TextAsset text = Resources.Load (path) as TextAsset;
if (null == text)
{
Debug.LogError ("can not find : " + path + " in OpengText", ResourceCommon.DEBUGTYPENAME);
}
return new MemoryStream (text.bytes);
}
}
public static StreamReader OpenText(string path)
{
return new StreamReader (Open (path), System.Text.Encoding.Default);
}
}