Arzie100 发表于 2022-4-22 08:24

Unity 实现AssetBundle动态加载预制体

1.AssetBundle类

首先在Assets目录下新建一个 Editor文件夹,把我们创建AssetBundle的脚本放在Editor里面,脚本名字就命名为AssetBundle。然后再创建一个命名为StreamingAssets的文件夹存放打包的文件,当然还需要有动态加载的预制体,选中需要AssetBundle动态加载的预制体,然后新建一个AssetBundle标记如下图所示


然后编写代码

private static void BundleAssetsBundle_Webgl()
{
   BuildAssetsBundle(BuildTarget.WebGL);
}
private static void BuildAssetsBundle(BuildTarget target)
{
   string packagePath = Application.streamingAssetsPath;
   if (packagePath.Length <= 0 && !Directory.Exists(packagePath))
   {
         return;
   }
   BuildPipeline.BuildAssetBundles(packagePath, BuildAssetBundleOptions.UncompressedAssetBundle, target);
}

这边BuildTarget我就以WebGl为例子了,路径为本地路径,这边就已经写好创建AssetBundle,下面我们要开始动态加载AssetBundle包。
2.AssetBundleMgr类

当我们把前面所需的都打包好了,现在我们要开始加载AssetBundle包了,然后开始编写代码
public static void DowloadAsset(string url, string name, Action<object> callback)
{
   new Task(GetAssetbundle(url, name, callback));//这边需要自己在写一个Task类
}

private static IEnumerator GetAssetbundle(string url, string name, Action<object> callback)
{
   var uwr = UnityWebRequestAssetBundle.GetAssetBundle(url + name);//获取动态加载路径
   yield return uwr.SendWebRequest(); //等待发送web请求
   AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(uwr);//下载AssetBundle包
   var loadAsset = bundle.LoadAssetAsync<GameObject>(name);//加载类型
   yield return loadAsset; //等待完成
   var prefab = loadAsset.asset;
   var go = GameObject.Instantiate(prefab); //克隆需要加载的包
   callback(go);
   bundle.Unload(false);
   Resources.UnloadUnusedAssets();//加载了包就要卸载
}3.Task类和TaskManager类

这个类可以在GitHub上直接复制过来,直接用就可以了
public class Task
{
        /// Returns true if and only if the coroutine is running.Paused tasks
        /// are considered to be running.
        public bool Running
        {
                get
                {
                        return task.Running;
                }
        }

        /// Returns true if and only if the coroutine is currently paused.
        public bool Paused
        {
                get
                {
                        return task.Paused;
                }
        }

        /// Delegate for termination subscribers.manual is true if and only if
        /// the coroutine was stopped with an explicit call to Stop().
        public delegate void FinishedHandler(bool manual);

        /// Termination event.Triggered when the coroutine completes execution.
        public event FinishedHandler Finished;

        /// Creates a new Task object for the given coroutine.
        ///
        /// If autoStart is true (default) the task is automatically started
        /// upon construction.
        public Task(IEnumerator c, bool autoStart = true)
        {
                task = TaskManager.CreateTask(c);
                task.Finished += TaskFinished;
                if (autoStart)
                        Start();
        }

        /// Begins execution of the coroutine
        public void Start()
        {
                task.Start();
        }

        /// Discontinues execution of the coroutine at its next yield.
        public void Stop()
        {
                task.Stop();
        }

        public void Pause()
        {
                task.Pause();
        }

        public void Unpause()
        {
                task.Unpause();
        }

        void TaskFinished(bool manual)
        {
                FinishedHandler handler = Finished;
                if (handler != null)
                        handler(manual);
        }

        TaskManager.TaskState task;
}

class TaskManager : MonoBehaviour
{
        public class TaskState
        {
                public bool Running
                {
                        get
                        {
                                return running;
                        }
                }

                public bool Paused
                {
                        get
                        {
                                return paused;
                        }
                }

                public delegate void FinishedHandler(bool manual);
                public event FinishedHandler Finished;

                IEnumerator coroutine;
                bool running;
                bool paused;
                bool stopped;

                public TaskState(IEnumerator c)
                {
                        coroutine = c;
                }

                public void Pause()
                {
                        paused = true;
                }

                public void Unpause()
                {
                        paused = false;
                }

                public void Start()
                {
                        running = true;
                        singleton.StartCoroutine(CallWrapper());
                }

                public void Stop()
                {
                        stopped = true;
                        running = false;
                }

                IEnumerator CallWrapper()
                {
                        yield return null;
                        IEnumerator e = coroutine;
                        while (running)
                        {
                                if (paused)
                                        yield return null;
                                else
                                {
                                        if (e != null && e.MoveNext())
                                        {
                                                yield return e.Current;
                                        }
                                        else
                                        {
                                                running = false;
                                        }
                                }
                        }

                        FinishedHandler handler = Finished;
                        if (handler != null)
                                handler(stopped);
                }
        }

        static TaskManager singleton;

        public static TaskState CreateTask(IEnumerator coroutine)
        {
                if (singleton == null)
                {
                        GameObject go = new GameObject("TaskManager");
                        singleton = go.AddComponent<TaskManager>();
                }
                return new TaskState(coroutine);
        }
}现在生成加载的代码我们都完成了,现在我们需要在需要动态加载的地方开始加载他们,例如我们在启动编辑器的时候就加载,那么我们就把加载写在Start函数里面就可以了:代码如下:
void Start()
{
    AssetsBundleMgr.DowloadAsset(Application.dataPath + "/StreamingAssets/", "cube", (go) =>
    {
      var scene = go as GameObject;
      //这里可以初始化该物体的各种属性
    });
}到这里就全部结束了。如果有觉得哪里有问题的地方欢迎指出,谢谢!
页: [1]
查看完整版本: Unity 实现AssetBundle动态加载预制体