unity W...

Unity中,使用资源加载系统加载资源

2024-03-31  本文已影响0人  全新的饭

说明

该资源系统提供如下方法:
通过名称异步加载预制体、场景、音频资源、精灵图等UnityObject。

当前还是将资源全部放在本地,通过该系统(而非其他方式,如直接Resources.Load)加载资源是为了方便后续改为从远端获取资源。

使用

  1. 根据快速开始 | YooAsset里的描述,安装YooAsset。

  2. 根据全局配置 | YooAsset里的描述,在Resources下创建YooAssetSettings。

  3. Assets下创建目录AssetsPackage,其下创建几个子目录AudioClips、Prefabs、Scenes、Sprites、……,将各类资源放到相应子目录下。

  4. YooAsset->AssetBundle Collector:创建Package,Enable Addressable打勾->Groups(上述每个子目录对应一个Group:子目录拖到Group的Collector处)

  5. YooAsset->AssetBundle Builder:BuildVersion设置为v1.0.0,CopyBuildinFileOption设置为Clear And Copy All(自动创建StreamingAssets\yoo,将所有资源包复制到该目录下)

  6. 如下是一个使用ResourceSys的例子(具体代码见后文):
    在Launch场景(唯一需要Build的场景)中有一Launcher,在其中初始化ResourceSys。完成后载入并进入目标场景,进入后游戏开始:载入预制体并创建副本、载入并播放音效、载入并将精灵图显示在Image上。

  7. 说明:在编辑器模式下,载入音效会报错,无法播放。但是打web包后可正常播放。因此在编辑器模式下初始化YooAsset使用编辑器模拟模式。

具体代码

FanResourceSys.cs

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using YooAsset;

public class FanResourceSys
{
    public static FanResourceSys Instance { get; private set; }
    public static bool TryInitialize(Action callback = null)
    {
        var ret = false;
        if (Instance == null)
        {
            Instance = new FanResourceSys(callback);
            ret = true;
        }
        return ret;
    }
    private const string PackageName = "DefaultPackage";
    private ResourcePackage _package;
    private FanResourceSys(Action initializeCallback)
    {
        YooAssets.Initialize();
        _package = YooAssets.CreatePackage(PackageName);
        YooAssets.SetDefaultPackage(_package);
        MonoSys.Instance.StartCoroutine(InitializeYooAsset(initializeCallback));

        IEnumerator InitializeYooAsset(Action initializeCallback)
        {
#if UNITY_EDITOR
            var initParameters = new EditorSimulateModeParameters();
            var simulateManifestFilePath = EditorSimulateModeHelper.SimulateBuild(EDefaultBuildPipeline.BuiltinBuildPipeline, PackageName);
            initParameters.SimulateManifestFilePath = simulateManifestFilePath;
            yield return _package.InitializeAsync(initParameters);
            initializeCallback?.Invoke();
#elif UNITY_WEBGL
            // string defaultHostServer = "http://localhost:8000/CDN/Test/v1.0.0";
            // string fallbackHostServer = "http://localhost:8000/CDN/Test/v1.0.0";
            string defaultHostServer = string.Empty;
            string fallbackHostServer = string.Empty;
            var initParameters = new WebPlayModeParameters();
            initParameters.BuildinQueryServices = new GameQueryServices();
            initParameters.RemoteServices = new RemoteServices(defaultHostServer, fallbackHostServer);
            var initOperation = _package.InitializeAsync(initParameters);
            yield return initOperation;

            if (initOperation.Status == EOperationStatus.Succeed)
            {
                Debug.Log("资源包初始化成功!");
                initializeCallback?.Invoke();
            }
            else
            {
                Debug.LogError($"资源包初始化失败:{initOperation.Error}");
            }
#else
            var initParameters = new OfflinePlayModeParameters();
            yield return _package.InitializeAsync(initParameters);
            initializeCallback?.Invoke();
#endif
        }
    }
    public void Destroy()
    {
        Instance = null;
    }

    #region 加载
    public void LoadPrefab(string name, Action<GameObject> callback)
    {
        LoadUnityObj(name, callback);
    }
    public void LoadScene(string name, Action callback)
    {
        var handle = _package.LoadSceneAsync(name, UnityEngine.SceneManagement.LoadSceneMode.Single, false);
        handle.Completed += h =>
        {
            callback?.Invoke();
        };
    }
    public void LoadAudioClip(string name, Action<AudioClip> callback)
    {
        LoadUnityObj(name, callback);
    }
    public void LoadSprite(string name, Action<Sprite> callback)
    {
        LoadUnityObj(name, callback);
    }
    public void LoadUnityObj<T>(string name, Action<T> callback) where T : UnityEngine.Object
    {
        var handle = _package.LoadAssetAsync<T>(name);
        handle.Completed += h =>
        {
            callback?.Invoke(h.AssetObject as T);
        };
    }
    #endregion

    #region 卸载
    public void UnloadUnusedAssets()
    {
        YooAssets.GetPackage(PackageName).UnloadUnusedAssets();
    }
    public void UnloadAllAssets()
    {
        YooAssets.GetPackage(PackageName).ForceUnloadAllAssets();
    }
    #endregion

    private class GameQueryServices : IBuildinQueryServices
    {
        public bool Query(string packageName, string fileName, string fileCRC)
        {
            return true;
        }
    }
    private class RemoteServices : IRemoteServices
    {
        private readonly string DefaultHostServer;
        private readonly string FallbackHostServer;
        public RemoteServices(string defaultHostServer, string fallbackHostServer)
        {
            DefaultHostServer = defaultHostServer;
            FallbackHostServer = fallbackHostServer;
        }
        public string GetRemoteFallbackURL(string fileName)
        {
            return FallbackHostServer;
        }

        public string GetRemoteMainURL(string fileName)
        {
            return DefaultHostServer;
        }
    }
}

Launcher.cs

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

public class Launcher : MonoBehaviour
{
    [SerializeField]
    private string _firstSceneName = "1";

    private void Start()
    {
        Init();
    }

    private void Update()
    {
        MyUpdate();
    }

    private void OnDestroy()
    {
        Destroy();
    }

    private void Init()
    {
        FanResourceSys.TryInitialize(() => FanResourceSys.Instance.LoadScene(_firstSceneName, GameStart));

        void GameStart()
        {
            FanResourceSys.Instance.LoadPrefab("Cube", prefab =>
            {
                var go = Instantiate(prefab);
                var au = go.AddComponent<AudioSource>();
                au.loop = true;
                FanResourceSys.Instance.LoadAudioClip("countdown", clip =>
                {
                    au.clip = clip;
                    au.Play();
                });
            });


            var canvas = new GameObject().AddComponent<Canvas>();
            canvas.renderMode = RenderMode.ScreenSpaceOverlay;
            var imgGo = new GameObject();
            imgGo.transform.SetParent(canvas.transform);
            imgGo.transform.localPosition = Vector3.zero;
            var img = imgGo.AddComponent<UnityEngine.UI.Image>();
            FanResourceSys.Instance.LoadSprite("Icon_Tx_04", sprite =>
            {
                img.sprite = sprite;
            });

        }
    }

    private void MyUpdate()
    {

    }

    private void Destroy()
    {

    }
}

先直接使用Resources加载

说明

  1. 先将所有资源放到Resources下,通过Resources加载:需传入相对Resources的路径,而非资源名称。
  2. 需要把场景添加到BuildSettings中。
  3. 所有资源都通过FanResourceSys加载,而不是直接调用Resources.Load。
  4. 方便后续将资源放在远端,修改加载方式。

使用Resources.Load的代码

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Mono.Cecil;
using UnityEngine;
using UnityEngine.SceneManagement;
using YooAsset;

public class FanResourceSys
{
    public static FanResourceSys Instance { get; private set; }
    public static bool TryInitialize(Action callback = null)
    {
        var ret = false;
        if (Instance == null)
        {
            Instance = new FanResourceSys();
            callback?.Invoke();
            ret = true;
        }
        return ret;
    }
    private FanResourceSys()
    {

    }

    public void Destroy()
    {
        Instance = null;
    }

    #region 加载
    public void LoadUnityObj<T>(string path, Action<T> callback) where T : UnityEngine.Object
    {
        var request = Resources.LoadAsync<T>(path);
        request.completed += oper =>
        {
            var asset = request.asset as T;
            if (asset != null)
            {
                callback.Invoke(asset);
            }
            else
            {
                Debug.LogError(path + " 读取失败!");
            }
        };
    }
    public void LoadPrefab(string path, Action<GameObject> callback)
    {
        LoadUnityObj(path, callback);
    }
    public void LoadAudioClip(string path, Action<AudioClip> callback)
    {
        LoadUnityObj(path, callback);
    }
    public void LoadSprite(string path, Action<Sprite> callback)
    {
        LoadUnityObj(path, callback);
    }
    public void LoadScene(string name, Action callback)
    {
        var oper = SceneManager.LoadSceneAsync(name);
        oper.completed += oper =>
        {
            callback?.Invoke();
        };
    }
    #endregion
    #region 卸载
    public void UnloadUnusedAssets()
    {
        Resources.UnloadUnusedAssets();
    }
    #endregion
}
上一篇 下一篇

猜你喜欢

热点阅读