unity Addressable系统及其Xlua脚本热更新全过程详细解析(二)

21 篇文章 1 订阅
17 篇文章 0 订阅
该博客介绍了如何在Unity中使用Addressables进行资源的异步加载、缓存管理和释放。通过AssetManager类,实现 GameObject 和其他UnityObject的加载、释放,并提供了Prefab和通用资源的加载示例。此外,还展示了XLuaClient的使用,用于加载Lua脚本。
摘要由CSDN通过智能技术生成

分享一下个人Demo工程:https://github.com/IsaWinding/AddressableXluaFramework.git
分享Addressable 资源加载:

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

public class AssetManager
{
    private static AssetManager instance;
    public static AssetManager Instance { get { if (instance == null) instance = new AssetManager();return instance; } }
    public UnityEngine.Transform PoolRoot;
    private Dictionary<string, GameObjectLoader> pools = new Dictionary<string, GameObjectLoader>();
    private Dictionary<GameObject, GameObjectLoader> lookup = new Dictionary<GameObject, GameObjectLoader>();
    public AssetManager()
    {
        UnityEngine.Transform poolNode = new GameObject("[Asset Pool]").transform;
        poolNode.transform.localPosition = Vector3.zero;
        poolNode.transform.localScale = Vector3.one;
        poolNode.transform.localRotation = Quaternion.identity;
        GameObject.DontDestroyOnLoad(poolNode);
    }

    /// <summary>
    /// 异步加载GameObject
    /// </summary>
    public void InstantiateAsync(string name, System.Action<GameObject> onFinish)
    {
        GameObjectLoader loader;
        if (this.pools.TryGetValue(name, out loader)){
            var obj = loader.Instantiate();
            this.lookup.Add(obj, loader);
            onFinish.Invoke(obj);
        }
        else{
            loader = new GameObjectLoader(name);
            var obj = loader.Instantiate();
            this.pools.Add(name, loader);
            this.lookup.Add(obj, loader);
            onFinish.Invoke(obj);
        }
    }
    /// <summary>
    /// GameObject
    /// </summary>
    public GameObject Instantiate(string name)
    {
        GameObjectLoader loader;
        if (this.pools.TryGetValue(name, out loader))
        {
            var obj = loader.Instantiate();
            this.lookup.Add(obj, loader);
            return obj;
        }
        else
        {
            loader = new GameObjectLoader(name);
            var obj = loader.Instantiate();
            this.pools.Add(name, loader);
            this.lookup.Add(obj, loader);
            return obj;
        }
    }
  
    /// <summary>
    /// 将资源释放回缓
    /// </summary>
    public void FreeGameObject(GameObject obj){
        if (obj != null){
            GameObjectLoader loader;
            if (this.lookup.TryGetValue(obj, out loader)){
                loader.Free(obj);
                this.lookup.Remove(obj);
            }
        }
    }
    public void RemovePools(string name){
        this.pools.Remove(name);
    }
    public void ReleaseAll(){
        foreach (var item in this.pools.Values){
            item.Release();
        }
    }
    /// <summary>
    /// 资源类型查找缓存表
    /// </summary>
    private Dictionary<string, UnityObjectLoader> assets = new Dictionary<string, UnityObjectLoader>();
    public T LoadAsset<T>(string name) where T : UnityEngine.Object{
        UnityObjectLoader loader;
        if (this.assets.TryGetValue(name, out loader)){
            var obj = loader.LoadAsset<T>();
            return obj as T;
        }
        else{
            loader = new UnityObjectLoader(name);
            var obj = loader.LoadAsset<T>();
            this.assets.Add(name, loader);
            return obj as T;
        }
    }

    /// <summary>
    /// 引用计数自减1,减少为0后释放Addressable
    /// </summary>
    public void FreeAsset(string name){
        UnityObjectLoader loader;
        if (this.assets.TryGetValue(name, out loader)){
            loader.Free();
        }
    }
}

资源加载实例:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
class UnityObjectLoader : BaseLoader
{
    private int objectRefCount = 0;
    private Object object_;
    public UnityObjectLoader(string name) : base(name){
        this.object_ = null;
    }
    public Object LoadAsset<T>() where T : UnityEngine.Object{
        if (object_ == null){
            object_ = base.Load<T>();
        }
        this.objectRefCount++;
        return object_;
    }
    public void Free(){
        this.objectRefCount--;
        Release();
    }
    public override void Release(){
        if (this.objectRefCount <= 0){
            base.Release();
            object_ = null;
            AssetManager.Instance.RemovePools(this.name);
        }
    }
}

Prefab 加载实例:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
class GameObjectLoader : BaseLoader{
    /// 资源缓存列表
    private Stack<GameObject> caches = new Stack<GameObject>();
    /// 正在使用的列表
    private HashSet<GameObject> references = new HashSet<GameObject>();
    public GameObject prefab;
    public GameObjectLoader(string name) : base(name){
        this.prefab = null;
    }
    public GameObjectLoader(GameObject obj) : base(obj.name){
        this.prefab = obj;
    }
    /// <summary>
    /// 同步方法,确保已经加载好了
    /// </summary>
    public GameObject Instantiate(Transform parent)
    {
        GameObject obj = null;
        if (caches.Count > 0){
            obj = caches.Pop();
        }
        else{
            obj = GameObject.Instantiate(this.prefab) as GameObject;
            obj.name = this.name;
        }
        this.references.Add(obj);
        return obj;
    }
    /// <summary>
    /// 同步方法实例化对象
    /// </summary>
    public GameObject Instantiate(){
        if (caches.Count > 0){
            var obj = caches.Pop();
            this.references.Add(obj);
            return obj;
        }
        else{
            if (this.prefab != null){
                var obj = GameObject.Instantiate(this.prefab) as GameObject;
                obj.name = this.name;
                this.references.Add(obj);
                return obj;
            }
            else{
                this.prefab = base.Load<GameObject>();
                var obj = GameObject.Instantiate(this.prefab) as GameObject;
                obj.name = this.name;
                base.Release();
                this.references.Add(obj);
                return obj;
            }
        }
    }
    public void Free(GameObject obj){
        this.caches.Push(obj);
        this.references.Remove(obj);
        obj.transform.SetParent(AssetManager.Instance.PoolRoot);
    }
    public override void Release(){
        foreach (var obj in this.caches){
            GameObject.Destroy(obj.gameObject);
        }
        if (this.references.Count <= 0){
            base.Release();
            AssetManager.Instance.RemovePools(this.name);
        }
    }
}

资源加载实例:

using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.Initialization;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine;
using System.Collections.Generic;

class BaseLoader
{
    protected string name = string.Empty;
    private AsyncOperationHandle handle;
    private bool isLoad = false;
    public BaseLoader(string name){
        this.name = name;
        this.isLoad = false;
    }

    /// <summary>
    /// 加载资源
    /// </summary>
    public virtual void Load<T>(System.Action<T> onComplete) where T : UnityEngine.Object
    {
        if (this.isLoad){
            if (handle.IsDone){
                if (onComplete != null){
                    onComplete(handle.Result as T);
                }
            }
            else
            {
                handle.Completed += (result) =>{
                    if (result.Status == UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationStatus.Succeeded)
                    {
                        var obj = result.Result as T;
                        if (onComplete != null){
                            onComplete(obj);
                        }
                    }
                    else
                    {
                        if (onComplete != null){
                            onComplete(null);
                        }
                        Debug.LogError("Load name = " + name + " tpye = " + typeof(T).ToString() + " failed!  ");
                    }
                };
            }
        }
        else
        {
            this.isLoad = true;
            this.handle = Addressables.LoadAssetAsync<T>(name);
            handle.Completed += (result) =>{
                if (result.Status == UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationStatus.Succeeded)
                {
                    var obj = result.Result as T;
                    if (onComplete != null){
                        onComplete(obj);
                    }
                }
                else{
                    if (onComplete != null){
                        onComplete(null);
                    }
                    Debug.LogError("Load name = " + name + " tpye = " + typeof(T).ToString() + " failed!  ");
                }
            };
        }
    }

    /// <summary>
    /// 同步方法加载资源
    /// </summary>
    public virtual T Load<T>() where T : UnityEngine.Object{
        this.isLoad = true;
        this.handle = Addressables.LoadAssetAsync<T>(name);
        T obj = this.handle.WaitForCompletion() as T;
        this.isLoad = false;
        return obj;
    }

    /// <summary>
    /// 同时加载多个资源
    /// </summary>
    public virtual List<T> Loads<T>() where T : UnityEngine.Object{
        this.isLoad = true;
        this.handle = Addressables.LoadAssetsAsync<T>(name, (obj) => { });
        List<T> objs = this.handle.WaitForCompletion() as List<T>;
        return objs;
    }
    public virtual void Release(){
        if (this.isLoad){
            this.isLoad = false;
            Addressables.Release(handle);
        }
    }
}

XLuaClient

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

public enum LuaLoaderType{ 
    LuaFile = 1,//lua的原文件读取模式
    LuaAddressableTxt = 2,//addressable 资源的读取模式
}
public class XLuaClient : MonoBehaviour{
    private static XLuaClient instance;
    private Dictionary<string, byte[]> bytesMap = new Dictionary<string, byte[]>();
    public static XLuaClient Instance { get { return instance; } }
    private static LuaEnv luaEnv;
    private const string FileRoot = "/XLuaFramework/Lua/";
    private const string AddressLuaTxtRoot = "Assets/_ABs/LuaTxt/";
    private LuaLoaderType loaderType = LuaLoaderType.LuaAddressableTxt;
    private void Awake(){
        instance = this;
        luaEnv = new LuaEnv();
        luaEnv.AddLoader(Loader);
        GameObject.DontDestroyOnLoad(this);
    }
    public void OnClear(){
        bytesMap.Clear();
    }
    public string LoadLuaString(string filePath){
        string string_;
        if (loaderType == LuaLoaderType.LuaFile){
            string_ = GetLuaFileText(filePath);
        }
        else{
            string_ = GetAddressableLuaString(filePath);
        }
        return string_;
    }
    public static string LoaderString(string filePath){
        var realFilePath = Application.dataPath + FileRoot + filePath + ".lua";
        var string_ = System.IO.File.ReadAllText(realFilePath);
        return string_;
    }
    public static string GetAddressableLuaTxtPath(string pFilePath){
        var path = AddressLuaTxtRoot + pFilePath + ".txt";
        return path;
    }
    public string GetAddressableLuaString(string filePath){
        var addressTxtPath = GetAddressableLuaTxtPath(filePath);
        var luaAssetText = AssetManager.Instance.LoadAsset<TextAsset>(addressTxtPath);
        return luaAssetText.text;
    }
    public string GetLuaFileText(string filePath){
        var realFilePath = Application.dataPath + FileRoot + filePath + ".lua";
        var string_ = System.IO.File.ReadAllText(realFilePath);
        return string_;
    }
    private byte[] Loader(ref string filePath){
        Debug.LogError("filePath" + filePath);
        if (bytesMap.ContainsKey(filePath))
            return bytesMap[filePath];
        var fixPath = filePath.Replace('.','/');
        var string_ = LoadLuaString(fixPath);
        var bytes = System.Text.Encoding.UTF8.GetBytes(string_);
        bytesMap.Add(filePath, bytes);
        return bytes;
    }
    public void StartMain(){
        luaEnv.DoString("require 'GameStartUp'");
    }
    public void DoString(string sring_){
        luaEnv.DoString(sring_);
    }
    private void OnDestroy() {
        luaEnv.Dispose();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值