找回密码
 立即注册
查看: 221|回复: 0

Unity资源管理和打包

[复制链接]
发表于 2023-2-25 21:07 | 显示全部楼层 |阅读模式
Unity资源读取:

  • RM: Resources.Load
  • Addressables: Addressables.LoadAssetAsync
  • AssetBundle:AssetBundle.Load
<hr/>问题:


  • 读取

    • RM:只能读取Resources文件夹下的(即路径中包含Resources),并且是按照相对路径读取
    • Addressables:需要手动设置group和key,再根据key去读取并且无法根据类型读取
    • AssetBundle:需要手动设置繁琐的依赖关系来达成最佳的内存利用率



  • 优化问题

    • RM:资源包无法分块读取,内存占用大,加载速度慢,需要一整块资源加载
    • Addressables:group关系并不影响内存关系,哪里需要加载哪里
    • AssetBundle:复杂的内存管理,一不小心就内存泄露了



  • 热更新

    • RM:不存在的 (ノ`Д)ノ
    • Addressables:快捷方便,通过group设置,可以自动对比出补丁包
    • AssetBundle:需要自己管理特征码和包体差异等对比


<hr/>我们需要:


  • 简单快捷的读取方式:不管是Resources文件夹以内的还是以外,根据文件名读取和根据类型读取
  • 复杂的依赖关系可以更易于管理:自动管理资源
  • 高效清晰并易于管理的内存管理:Adressables的非依赖的资源读取方式
  • 快捷方便的热更新方案:自动检测出补丁包以便增量更新
<hr/>ResourcesManager-基于Addressables和RM整合出一套资源管理和打包流程

<hr/>简单快捷的读取方式

1. 以文件名为key,建立资源映射表




  • Refresh all directroy information 刷新映射表
  • Directories 目标文件夹
  • Exclude Directories 排除的文件
  • Ignore Extensions 忽略的文件类型
  • Auto Detect 是否在文件导入或移动时自动刷新



  • 映射表

    • 后缀
    • 父级文件
    • Unity类型

  • 注意事项:同名文件会被强制加入_type,如GameObject.prefab有同名的话会变化GameObject_prefab.prefab
<hr/>2. 读取资源的接口

/// <summary>
/// Load resources according to name
/// </summary>
/// <typeparam name="T">Any types Inherited from UnityEngine.Object</typeparam>
/// <param name="assetName">Resource name</param>
/// <returns>Resource</returns>
public T LoadFromName<T>(string assetName) where T : UnityEngine.Object ···

/// <summary>
/// Async load resources according to name
/// </summary>
/// <typeparam name="T">Any types Inherited from UnityEngine.Object</typeparam>
/// <param name="assetName">Resource name</param>
/// <param name="callback">Callback will be invoke when load done</param>
/// <returns>Coroutine for async</returns>
public Coroutine LoadFromNameAsync<T>(string assetName, Action<T> callback) where T : UnityEngine.Object ···

internal T LoadFromNameInernal<T>(string assetName, Action<T> callback, out Coroutine coroutine) where T : UnityEngine.Object ···
internal IEnumerator Load<T>(string assetName, Action<T> callback) where T : UnityEngine.Object ···

  • 根据名字读取资源

    • LoadFromName:同步读取资源,所有被包括在映射表内的资源都可以直接用这个方法

      • 内部用了Resources.Load和Addressables.LoadAssetAsync的接口
      • 注意:Addressables的同步读取接口是官方非正式公开的,可能有点问题
      • 目前Addressables也没有开放根据type来读取资源的接口,只有泛型

    • LoadFromNameAsync:异步读取接口,其他同上

/// <summary>
/// Load all types of target
/// </summary>
/// <typeparam name="T">Any types Inherited from UnityEngine.Object</typeparam>
/// <param name="path">Optional: Start such as Resources/Folder</param>
/// <returns>List for all resources</returns>
public List<T> LoadFromType<T>(string path = null) where T : UnityEngine.Object ···

/// <summary>
/// Load all types of target
/// </summary>
/// <param name="type">Any types Inherited from UnityEngine.Object</param>
/// <param name="path">Optional: Start such as Resources/Folder</param>
/// <returns>List for all resources</returns>
public List<UnityEngine.Object> LoadFromType(Type type, string path = null) ···

/// <summary>
/// Async load all types of target
/// </summary>
/// <typeparam name="T">Any types Inherited from UnityEngine.Object</typeparam>
/// <param name="callback">Callback will be invoke when load done</param>
/// <param name="path">Optional: Start such as Resources/Folder</param>
public void LoadFromTypeAsyn<T>(Action<List<T>> callback, string path = null) where T : UnityEngine.Object ···

/// <summary>
/// Async load all types of target
/// </summary>
/// <param name="type">Any types Inherited from UnityEngine.Object</param>
/// <param name="callback">Callback will be invoke when load done</param>
/// <param name="path">Optional: Start such as Resources/Folder</param>
public void LoadFromTypeAsyn(Type type, Action<List<UnityEngine.Object>> callback, string path = null) ···

internal List<UnityEngine.Object> LoadFromTypeInternal(Type type, string path = null, Action<List<UnityEngine.Object>> callback = null) ···

  • 根据类型读取资源

    • LoadFromType:同步读取path路径下所有type的资源,如果path为空,则遍历映射表

      • Resources.Load、Addressables.LoadAssetAsync
      • 根据映射表的Unity类型读取
      • 非Resources的同步接口同上,只能用AssetDataBase

    • LoadFromTypeAsync:异步读取接口,其他同上

<hr/>自动管理资源


  • 通过资源导入或移动的事件(AssetPostprocessor)回调修改映射表
  • 自动添加或修改删除Addressables中的Group和Entry,当资源未被指定Addressables时,自动加入到Temp(Group)中
<hr/>示例


  • 将Static Resources加入到ResoucesManager的Directories中


2. 确认添加之前的状态,映射表和Addressables




3. 加入GameObject1的预设到Static Resources中


4.  映射表自动加入了GameObject1的映射关系,Addressables也自动加入到Default(Group)并创建一个Entry用于GameObject1的定向




5. Build Player Content


6. 选择Pack Play Mode(模拟实机加载)



7. 代码加载
public class Test : MonoBehaviour
{
    private void Start()
    {
        ResourcesManager.instance.LoadFromNameAsync<GameObject>("GameObject1", go => { Instantiate(go); });
    }
}
8. 没问题


Adressables的非依赖的资源读取方式

参考之前写的资源管理
增量更新


  • 官方文档
  • 无需在导入或修改时特地分离出更新内容,自动快捷地自动识别出需要更新的资源,并分到到单独一个Group里面,打出单独的asset包用于增量更新
<hr/>

  • 给Group指定好Static Content注明Group中的内容是静态不会更新的



  • 打包


2. 来到相关资源包文件夹检查


3. 修改GameObject2(pos.x+1),新增GameObject3
4. 选择Prepare For Content Update


5. 选择Asset/AddressableAssetsData内的bin文件(记录了上次资源包的相关内容)


6. 检测出相关新增和修改,将相关的Entry会移动到Content Update(Group)中




7. 修改Content Update的设置


8. 再次打包,相关资源包文件夹多出了用于增量更新的资源



Addressables的同步读取

参考自Unity官方示例

  • 脚本中加入官方示例中的两个脚本


2. 看了看脚本核心部分,其实重写解包和读取资源的方式,用了AssetBundle
3. Default Group设置解包和读取资源的Provider
注意:一定要设置Default的Group,而且资源所在Group也需要,我这里就讲需要打包资源所在Group设为Default了


4. 打包
5.脚本读取
private void Start()
{
    StartCoroutine(Load());
}
private IEnumerator Load()
{
    //由于Addressables的初始化是异步过程,MainThread无法通过进程阻塞来等待初始化完成,只能这样了
    yield return ResourcesManager.instance.inited;
    //第一次异步读取需要等待初始化,之后就不需要了
    Instantiate(ResourcesManager.instance.LoadFromName<GameObject>("Cube"));
    Instantiate(ResourcesManager.instance.LoadFromName<GameObject>("GameObject1"));
}
//ResoucesManager内部相关读取
var handle = Addressables.LoadAssetAsync<T>(assetName);
if (handle.IsValid() && handle.Status == AsyncOperationStatus.Succeeded)
{
    if (callback == null)
    {
        if (handle.IsDone)
        {
            return handle.Result;
        }
    }
    ···
}
6. 实机运行,没问题

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-6-27 14:15 , Processed in 0.098266 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表