unity-AssetBundle

  今天开始unity热更新的真正核心,在做unity动态热更新的时候,查看网上的一些资料,发现unity给的官方AssetBundle方案,只可以实现资源的热更新,无法实现脚本代码的热更新,当然也有一些方案来实现脚本代码的热更新,在这里就天马行空的展开下(关于脚本热更新部分皆为互联网所得,没有经过验证,这里留下脚印,以备后用),网上最多提及的是如下这几种方案:uLua、uLua&cstoLua、sLua,而这三种方案的优缺在这里就不在做“搬运工”了,将来有机会做了实验之后在如实做下记录。

  上一段主要说了些题外话,其实这篇文章主要说明的还是采用的AssetBundle的资源热更新技术,这个现在是一个成熟的技术方案,可以对图片、声音、模型等资源进行动态热更新,但是基本推荐的技术是将预制体或场景打为AssetBundle然后再进行使用,当然最优的方案还是将预制体打为AssetBundle进行使用。

  还有就是一个比较重要的问题就是,有时某些资源在打完AssetBundle后,在使用时,会出现一些物体渲染不出来的问题,这个主要是跟sharder没有打到AssetBundle中有关,所以在打AssetBundle前添加上你所需的shader,位置Project Setting中的Graphics Settings中添加上所需shader,然后再打AssetBundle。

  下面先来一段打AssetBundle的代码:

  

using UnityEngine;
using System.Collections;
using UnityEditor;

using System.IO;

public class AssetBundleTest : Editor
{

    //将视图选择的文件夹下所有游戏对象打成一个AssetBundle包-安卓
    [MenuItem("Custom Editor/Android/Create AssetBunldes ALL 3DA")]
    static void CreateAndroidAssetBunldesALL3DA()
	{
        createAndroidAll("ALL-3DA");
	}

    [MenuItem("Custom Editor/Android/Create AssetBunldes ALL 3DB")]
    static void CreateAndroidAssetBunldesALL3DB()
    {
        createAndroidAll("ALL-3DB");
    }
    [MenuItem("Custom Editor/Android/Create AssetBunldes ALL 3DC")]
    static void CreateAndroidAssetBunldesALL3DC()
    {
        createAndroidAll("ALL-3DC");
    }
	[MenuItem("Custom Editor/Android/Create AssetBunldes ALL MovA")]
	static void CreateAndroidAssetBunldesALLMovA()
	{
		createAndroidAll("ALL-MovA");
	}
	[MenuItem("Custom Editor/Android/Create AssetBunldes ALL MovB")]
	static void CreateAndroidAssetBunldesALLMovB()
	{
		createAndroidAll("ALL-MovB");
	}
	
	static void createAndroidAll(string name)
    {
        string str = CheckOperationName();
        if (str != "android")
        {
            Debug.LogError("操作错误!请选择Android分支");
            return;
        }

        Caching.CleanCache();

        string Path = Application.dataPath + "/StreamingAssets/"+name+".assetbundle";

        //获取在Project视图中选择的所有游戏对象
        Object[] SelectedAsset = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
      
        foreach (Object obj in SelectedAsset)
        {
            Debug.Log("Create AssetBunldes name :" + obj);
        }
        //打包资源
        //注释掉的这两句为5.3.0前版本采用的AssetBundle打包方式没有LZ4压缩-第一句目标web,第二句目标安卓,第三句目标安卓
        //if (BuildPipeline.BuildAssetBundle(null, SelectedAsset, Path, BuildAssetBundleOptions.UncompressedAssetBundle | BuildAssetBundleOptions.CollectDependencies, BuildTarget.WebPlayer))
        //if (BuildPipeline.BuildAssetBundle(null, SelectedAsset, Path, BuildAssetBundleOptions.UncompressedAssetBundle | BuildAssetBundleOptions.CollectDependencies, BuildTarget.Android))
        if (BuildPipeline.BuildAssetBundle(null, SelectedAsset, Path, BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.CollectDependencies, BuildTarget.Android))
        {
            AssetDatabase.Refresh();
        }
        else
        {
        }
    }

    //将视图选择的文件夹下所有游戏对象打成一个AssetBundle包-IOS
    [MenuItem("Custom Editor/IOS/Create AssetBunldes ALL 3DA")]
    static void CreateIOSAssetBunldesALL3DA()
    {
        createIOSAll("ALL-3DA-IOS");
    }

    [MenuItem("Custom Editor/IOS/Create AssetBunldes ALL 3DB")]
    static void CreateIOSAssetBunldesALL3DB()
    {
        createIOSAll("ALL-3DB-IOS");
    }
    [MenuItem("Custom Editor/IOS/Create AssetBunldes ALL 3DC")]
    static void CreateIOSAssetBunldesALL3DC()
    {
        createIOSAll("ALL-3DC-IOS");
    }
    [MenuItem("Custom Editor/IOS/Create AssetBunldes ALL MovA")]
    static void CreateIOSAssetBunldesALLMovA()
    {
        createIOSAll("ALL-MovA-IOS");
    }
    [MenuItem("Custom Editor/IOS/Create AssetBunldes ALL MovB")]
    static void CreateIOSAssetBunldesALLMovB()
    {
        createIOSAll("ALL-MovB-IOS");
    }

    static void createIOSAll(string name)
    {

        string str = CheckOperationName();
        if (str != "ios")
        {
            Debug.LogError("操作错误!请选择IOS分支");
            return;
        }

        Caching.CleanCache();

        string Path = Application.dataPath + "/StreamingAssets/" + name + ".assetbundle";

        //获取在Project视图中选择的所有游戏对象
        Object[] SelectedAsset = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);

        foreach (Object obj in SelectedAsset)
        {
            Debug.Log("Create AssetBunldes name :" + obj);
        }
        
        //打包资源
        //注释掉的这两句为5.3.0前版本采用的AssetBundle打包方式没有LZ4压缩-第一句目标web,第二句目标IOS,第三句目标IOS
        //if (BuildPipeline.BuildAssetBundle(null, SelectedAsset, Path, BuildAssetBundleOptions.UncompressedAssetBundle | BuildAssetBundleOptions.CollectDependencies, BuildTarget.WebPlayer))
        //if (BuildPipeline.BuildAssetBundle(null, SelectedAsset, Path, BuildAssetBundleOptions.UncompressedAssetBundle | BuildAssetBundleOptions.CollectDependencies, BuildTarget.iOS))
        if (BuildPipeline.BuildAssetBundle(null, SelectedAsset, Path, BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.CollectDependencies, BuildTarget.iOS))
        {
            AssetDatabase.Refresh();
        }
        else
        {
        }
    }
	
	[MenuItem("Custom Editor/Create Scene")]
	static void CreateSceneALL ()
	{
		//清空一下缓存
		Caching.CleanCache();
        string Path = Application.dataPath + "/StreamingAssets/MyScene.unity3d";
		string  []levels = {"Assets/Level.unity"};
    	//打包场景
        BuildPipeline.BuildPlayer(levels, Path, BuildTarget.Android,BuildOptions.BuildAdditionalStreamedScenes);

		AssetDatabase.Refresh ();
	}

    [MenuItem("Custom Editor/TestCheckOperation")]
    static void CheckOperation()
    {
        string name = CheckOperationName();

        Debug.LogError("操作分支:"+name);
    }

    static string CheckOperationName()
    {
        string osSting =
#if UNITY_ANDROID
 "android";
#elif UNITY_IPHONE
        "ios";
#else
        "qita";
#endif
        return osSting;
    }
}
  上面代码为Editor代码,需要放入项目的Editor文件夹中。在上面代码共有四种功能,打安卓的AssetBundle,打ios的AssetBundle,打安卓的场景AssetBundle,检测当前所处分支。

  打资源AssetBundle的方法是用鼠标选中资源或资源所处位置。如下图所示:


  还有就是网上有的人说在windows系统下不能打ios的AssetBundle,打出来的AssetBundle不可用,最后在实际项目中经过验证发现并不是这样的,只需要在打android与ios的AssetBundle时(我们windows系统打ios跟安卓的AssetBundle,应用到不同平台完全没有问题,但是注意iOS跟安卓一定要分开打,选择相对应的BuildTarget),在Build Setting选择对应的分支平台,如下图为android分支平台:


  若要选择ios分支平台,需要展开ios对应tab,如图所示,然后再点击button(Switch Platform),等一段时间进行切换(视项目资源多少,切换时间差异很大)。




下面开始记录下AssetBundle的使用部分,依然还是先贴上代码:

using UnityEngine;
using System.Collections;

public class RunScript : MonoBehaviour
{
    public AudioSource mAudio;

    private static AssetBundle mDownload=null;

    private string debugLog = "";
        //不同平台下StreamingAssets的路径是不同的,这里需要注意一下。
        //public static readonly string PathURL =
    public static string PathURL =
#if UNITY_ANDROID
        //"jar:file://" + Application.dataPath + "!/assets/";
        Application.dataPath + "!assets/";
#elif UNITY_IPHONE  
        Application.dataPath + "/Raw/";
#elif UNITY_STANDALONE_WIN || UNITY_EDITOR
        //"file://" + Application.dataPath + "/StreamingAssets/";
     Application.dataPath + "/StreamingAssets/";
#else
    string.Empty;
    //Application.dataPath + "/StreamingAssets/";  
#endif

        void Start()
        {
#if UNITY_ANDROID
            Debug.Log("UNITY_ANDROID");
            debugLog += "UNITY_ANDROID"+"\n";
#elif UNITY_IPHONE
		Debug.Log("UNITY_IPHONE"); 
            debugLog += "UNITY_IPHONE"+"\n";
#elif UNITY_STANDALONE_WIN || UNITY_EDITOR
            Debug.Log("UNITY_STANDALONE_WIN || UNITY_EDITOR");
            debugLog += "UNITY_STANDALONE_WIN || UNITY_EDITOR" + "\n";
#else
    Debug.Log("else"); 
            debugLog += "else"+"\n";
#endif
#if UNITY_EDITOR
            PathURL = Application.dataPath + "/StreamingAssets/";
#endif
        }
        void OnGUI()
	{
       
        GUI.Label(new Rect(0,60,Screen.width,Screen.height),debugLog);
		if(GUILayout.Button("ALL Assetbundle"))
		{
			
            StartCoroutine(LoadAllGameObject());
		}
		
		if(GUILayout.Button("Open Scene"))
		{
			
            StartCoroutine(LoadSceneCreatFromFile());
		}

        if (GUILayout.Button("Open game1"))
        {
            LoadGame1test();
            
        }
        if (GUILayout.Button("Open game2"))
        {
            LoadGame2Test();
            
        }
		
	}
	

    //加载assetBundle获得场景并载入
    private IEnumerator LoadSceneCreatFromFile()
    {
       
        AssetBundle download = AssetBundle.LoadFromFile(PathURL + "MyScene.unity3d");
        yield return download;
        //var bundle = download.assetBundle;
        Application.LoadLevel("Level");
    }

    //加载assetBundle获得预制体与音频
    private IEnumerator LoadAllGameObject()
    {
        Debug.Log(PathURL + "ALL-3DA-IOS.assetbundle");
        debugLog += PathURL + "ALL-3DA-IOS.assetbundle" + "\n";
        AssetBundle download = AssetBundle.LoadFromFile(PathURL + "ALL-3DA-IOS.assetbundle");

        yield return download;
        GameObject obj = GameObject.Instantiate(download.LoadAsset("Prefab0")) as GameObject;
        debugLog += obj + "\n";
        Debug.Log(obj);
        obj.transform.position = new Vector3(0, 0, 0);
        GameObject obj1 = GameObject.Instantiate(download.LoadAsset("art")) as GameObject;
        debugLog += obj1 + "\n";
        Debug.Log(obj1);
        obj1.transform.position = new Vector3(0, 0.1f, 0);

        mAudio.clip = download.LoadAsset("art.mp3") as AudioClip;
        mAudio.Play();
    }

    private IEnumerator LoadGame1()
    {
        if (mDownload == null)
        {
            Debug.Log(PathURL + "ALL.assetbundle");
            debugLog += PathURL + "ALL.assetbundle" + "\n";
            mDownload = AssetBundle.LoadFromFile(PathURL + "ALL.assetbundle");
        }
        yield return mDownload;
        GameObject obj = GameObject.Instantiate(mDownload.LoadAsset("Prefab0")) as GameObject;
        debugLog += obj + "\n";
        Debug.Log(obj);
        obj.transform.position = new Vector3(0, 0, 0);
        
    }

    private IEnumerator LoadGame2()
    {
        if (mDownload == null)
        {
            Debug.Log(PathURL + "ALL.assetbundle");
            debugLog += PathURL + "ALL.assetbundle" + "\n";
            AssetBundle download = AssetBundle.LoadFromFile(PathURL + "ALL.assetbundle");
        }
        yield return mDownload;

        GameObject obj1 = GameObject.Instantiate(mDownload.LoadAsset("art")) as GameObject;
        debugLog += obj1 + "\n";
        Debug.Log(obj1);
        obj1.transform.position = new Vector3(0, 0.1f, 0);  
    }

    private void LoadGame1test()
    {
        if (mDownload == null)
        {
            Debug.Log(PathURL + "ALL.assetbundle");
            debugLog += PathURL + "ALL.assetbundle" + "\n";
            mDownload = AssetBundle.LoadFromFile(PathURL + "ALL.assetbundle");
        }
       
        GameObject obj = GameObject.Instantiate(mDownload.LoadAsset("Prefab0")) as GameObject;
        debugLog += obj + "\n";
        Debug.Log(obj);
        obj.transform.position = new Vector3(0, 0, 0);

    }

    private void LoadGame2Test()
    {
        if (mDownload == null)
        {
            Debug.Log(PathURL + "ALL.assetbundle");
            debugLog += PathURL + "ALL.assetbundle" + "\n";
            AssetBundle download = AssetBundle.LoadFromFile(PathURL + "ALL.assetbundle");
        }
        

        GameObject obj1 = GameObject.Instantiate(mDownload.LoadAsset("art")) as GameObject;
        debugLog += obj1 + "\n";
        Debug.Log(obj1);
        obj1.transform.position = new Vector3(0, 0.1f, 0);
    }
	
    public void testAudio(){
        mAudio.clip = (AudioClip)Resources.Load("art", typeof(AudioClip));
        mAudio.Play();
    }
}
上面的代码主要是使用unity5.4.0调试出来的,unity的版本在5.3.0时对AssetBundle进行了一些修订,所以这个版本前后可能会出现一些API不兼容的问题,出现这个问题还需要自己进行调整下,在这里特此说明。

对于AssetBundle的使用,避免不了的就是对于AssetBundle的卸载:

  • Unload

该方法会卸载运行时内存中包含在bundle中的所有资源。
当传入的参数为true,则不仅仅内存中的AssetBundle对象包含的资源会被销毁。根据这些资源实例化而来的游戏内的对象也会销毁。
当传入的参数为false,则仅仅销毁内存中的AssetBundle对象包含的资源。

而在对于大量图片,最好是使用异步加载的方式,大体代码如下:

Texture frameAniTex;
			
AssetBundleRequest mRequest = mDownLoad.LoadAssetAsync(textureName + "_" + currentIndex.ToString("D5"),typeof(Texture));

frameAniTex = mRequest.asset as Texture;

今天暂时能够想到的就暂时就这些了。

最后在这里还是需要重申由于安卓不同路径下的读写权限的问题,所以在实验assetbundle热更新的时候,路径地址Application.persistentDataPath。

demo地址:http://download.csdn.net/detail/xunni_5241/9623036

本人文章纯属个人总结,且某些demo在项目采用前可能来自互联网,最终实验验证后实际项目中采用,若发现来自贵方,谅解;若发现,纰漏错误妄指正。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xunni_5241

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值