打包资源,加载资源已经是ungity3d很常见的事了,其中为了自己的资源不被别人抄袭,经常会将已经打包好的“xx.unity3d”机密,一种是在外边加一次“保护膜”(比如建个文件夹,把文件夹加密,这种我没研究过),另一种就是把“.unity3d”包转换成“.byte”文件,把转换好的“.byte”文件用一定的规律乱掉(规律要记好,解密时还要用),然后再把“.byte”文件打包成“.unity3d”文件,这样打包完的“.unity3d”资源包必须经过两次加载和一次生成才能使用,第一次是加载成“.byte”文件,然后将“.byte”文件生成“.unity3d”虚拟资源包,最后再加载生成的虚拟资源包里的真实资源(中间需要解密)。 打包资源我就不谈论了,网上有具体的代码,今天主要说说解密时遇到的问题,把".byte"文件加载成“.unity3d”包需要用到AssetBundle.CreateFromMemory(byte[] bytes)方法,这是一个从内存字节生成资源包的方法,返回的是 AssetBundleCreateRequest类型,同是返回的有一个数据流,这就需要用到协同程序(主要是yield return AssetBundleCreateRequest),而第一次加载也需要用到协同程序,因此网上给了一种协同里面套协同的方法。我试着用了一下,发现这个加载脚本需要继承MonoBehaviour类,但是加载资源的脚本里面不需要用到Start()和Update()方法,只是写了一些公开的方法而已,因此不必继承 MonoBehaviour类,因此StartCoroutine方法就不能使用,所以网上给的协同里面套协同就不合适了,于是我就开始了苦逼的一天。 开始我想在第一次加载的方法(LoadAsset())里面另开个线程,通过线程调用第二次加载(LoadBundle())方法,但是系统报错,说IEnumerator调用必须在主线程中,我郁闷了,所以我就开始查关于AssetBundleCreateRequest的文档,并开始用普通方法调用:因为IEnumerator返回的肯定是IEnumerator类,所以我声明了一个IEnumerator类型的ie变量接受IEnumerator的返回值,然后调用IEnumerator.MoveNext()方法,这样就把AssetBundleCreateRequest类返回给我了,我开始很高兴,因为得到AssetBundleCreateRequest后就可以通过AssetBundleCreateRequest.progress和AssetBundleCreateRequest.isDown查看进度,等到AssetBundleCreateRequest.progress >=1就表明“.unity3d”包创建完成(这是虚拟包,可以直接加载),然后我就可以加载,最后实例化,这就完成了,但是事实没有我想的那么完美,出现了一个意想不到事情,AssetBundleCreateRequest.progress和AssetBundleCreateRequest.isDown竟然不同步,progress显示的是1,按说isDown应该是true,但事实却是false,这很让我费解,然后我就去查这两个到底代表了什么意思,最后发现progress确实是下载进度,但isDown确是是否完成操作,也就是AssetBundleCreateRequest这个异步操作是否完成,这就坑爹了,AssetBundleCreateRequest是继承了AsyncOperation 类,但是这是unity3d自己封装的,不是c#封装的,官网上也没明确给出AsyncOperation 异步操作的终止方法,等于说打了个死结了。就在我以为只能认命时(脚本继承MonoBehaviour)时,突然发现自己脑残了,你妹的别人博客上把二个协同写成一个套一个,我可以把两个协同写在一起啊,一个yield return WWW,一个yield return AssetBundleCreateRequest。完全可以解决不必继承MonoBehaviour的事情,至于为什么这么做,下次再说吧,下面我将代码传上。 - public class ResourceManager
- {
- bool isloadfromCache = true;//是否从缓存加载
- private static ResourceManager resourceManager;
- int m_CacheVersion = 5;//版本号
- //实例化
- public static ResourceManager getInstance()
- {
- if(resourceManager == null)
- {
- resourceManager = new ResourceManager();
- }
- return resourceManager;
- }
- //构造方法
- public ResourceManager()
- {
- //我用的是本地加载,网络需要用“http://”
- mResourcePath = "file://" + Application.dataPath;
- }
- //协同程序,需要用StartCoroutine()方法调用,可以外部调用
- public IEnumerator LoadAsset(string fileName)
- {
- string fullurl = mResourcePath + "/" + "Unity3d/"+fileName+".unity3d"; //加载路径
- WWW m_Download;
- if(isloadfromCache){
- m_Download = WWW.LoadFromCacheOrDownload(fullurl,m_CacheVersion);
- }else{
- m_Download = new WWW(fullurl);
- }
- //第一次协同
- yield return m_Download;
- if(m_Download.error != null)
- {
- // Debug.LogError(m_Download.error);
- Debug.Log("Warning errow"+fileName);
- yield break;
- }
- //第一次加载
- TextAsset txt = m_Download.assetBundle.Load(fileName,typeof(TextAsset)) as TextAsset;
- byte[] data = txt.bytes;
- byte[] decryptedData = Decryption(data);
- //打成虚拟包
- AssetBundleCreateRequest acr = AssetBundle.CreateFromMemory(decryptedData);
- //原本要第二次协同
- yield return acr;
- AssetBundle bundle = acr.assetBundle;
- //第二次加载
- bundle .LoadAll();
- Instantiate(bundle.mainAsset);
- }
- byte[] Decryption(byte[] data){
- //解密算法,这个要自己写,你加密时是怎样,这里反过来
- }
- }
复制代码 |