1)关于 Addressables 做启动热更资源的路径问题
​2)Unity 2018 Android 平台 Blit Type 设置为 Never 时画面会变暗
3)视频压缩方案
4)关于 AssetBundle 中的资源冗余的问题
5)Addressable 如何让加载的时候不对比服务器


这是第 221 篇 UWA 技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间 10 分钟,认真读完必有收获。

UWA 问答社区:answer.uwa4d.com
UWA QQ 群 2:793972859(原群已满员)

Addressable

Q:关于 Addressables 做启动热更资源的路径问题,将部分资源在可寻址系统里打入了 StreamAssets,并将资源设置 Cannot Release。打出程序后修改资源,做热更流程,然后运行程序也正常检测热更并下载,但是下载的更新 AssetBundle 包并不在 PersistentDataPath 路径下。如果是在同一机器下,热更包会在 Unity 编辑器的 Temp 路径下找到,可是我将程序拿到什么都没装的新电脑下,程序还是能检测热更下载,但 PersistentDataPath 仍然看不到热更 AssetBundle,求解。

A1:Addressable 下载更新用的是缓存的方式,所以不会在 PersistentDataPath 里面,会在应用的默认缓存目录里面,如下图:

如果需要修改缓存的路径,这个可以试下:

最后拉进去 AddressableAssetSettings 的 Initialization Object 列表里就行。

感谢 Toushirou@UWA 问答社区提供了回答

A2:感谢您的帮助,该方式确实可以重写缓存路径。值得注意的是 Cache Directory Override 并不能完全像 Addressables Profiles 里路径一样配置可变路径,只支持了带 “{}” 的方式,如{UnityEngine.Application.persistentDataPath},带 “[]” 则不支持配置。再次感谢层主的帮助!

另外,上层 Cache Directory Override 最终调用的源码,可根据自己的需求拓展,如下图:

感谢题主兮风@UWA问答社区提供了回答

A3:在安卓手机上安装一个 apk,并且运行之后,假设这个 apk 的包名叫 com.x.y,会在安卓手机上多 3 个目录:
目录 1:sdcard/Android/data/com.x.y,这个目录下有一个 cache 目录。
目录 2:data/app/com.x.y-1,这个目录下有目录 lib 和目录 oat,还有一个 base.apk。
目录 3:data/data/com.x.y,这个目录下有有 5 个目录,files,shared_prefs,cache,code_cache,lib。
上面的目录 1 的 sdcard 和目录 2 的 data 是同级的。目录 2 和目录 3 需要 root 才能看到,没有 root 的手机应该是只能看到 sdcard 下面的文件。

当我运行 Addressable 进行远程加载资源后,在目录 1 里面多了一个与 cache 同级的 files 目录,这个 files 目录应该就是 Application.persistentDataPath。在这个 files 目录里面会多两个目录,分别是 com.unity.addressables,这里面放的是 catalog.hash 和 catalog.json,另外一个是 UnityCache 目录,里面有两个目录,Shared 和 Temp,Temp 是空的,Shared 里面放的是下载的 AssetBundle。

Addressable 使用的是 Caching 机制,所以是可以通过类似于 Caching.currentCacheForWriting = Caching.AddCache(“D:/Shalou/UnityCaching/”);这样的操作在 PC 上更改缓存目录的,在 Android 平台上应该也是可以的,这个就和安卓的权限有关系了,没有做进一步的测试。猜测是,如果没有开启 External 的 Write Permission,只能在目录 1 下面的 files 目录里面进行目录替换了,也就是只能在 Application.persistentDataPath 后面添加子目录来更改缓存目录。

在 PC 上,题主说的默认的缓存和 persistentDataPath 确实是两个路径,如下图:

感谢 Xuan@UWA 问答社区提供了回答

Rendering

Q:有看到说 Blit Type 设置为 Always 会多出一次 Blit 操作,在 2018 下在真机测试了下出现类似对比度变大,画面变暗的效果。改回 Always 就正常。
色彩空间为线性空间。
这项设置有什么讲究?

A:AndroidBlitType.Never 不提供 sRGB 后备缓冲区。线性渲染需要一个执行 sRGB 读/写转换的帧缓冲区(请参阅 RenderTexture.sRGB),否则生成的图像通常显得太暗。因此,在使用线性渲染时,不建议使用 AndroidBlitType.Never。如果想使用 AndroidBlitType.Never 进行线性渲染,尽管有这些信息,您仍然必须设置自己的 sRGB 渲染目标并处理针对后备缓冲区的 Blit 操作。

可以参考一下网址:

https://docs.unity.cn/cn/current/ScriptReference/AndroidBlitType.html
https://docs.unity3d.com/ScriptReference/AndroidBlitType.html

感谢小埃拉@UWA问答社区提供了回答

Video

Q:请教一下,对于视频来讲有什么比较合适的压缩方案?目前我们原始视频有近 60MB,准备压缩后放入 StreamingAssets 下,读取解压后播放。除了对 VideoClip 本身做处理外,还有其他方案么?希望 Android 和 iOS 平台都通用。

A1:可以试试压缩成 H.264 或者 H.265 编码的 MP4 格式视频。

感谢马三小伙儿@UWA问答社区提供了回答

A2:H.264 兼容各平台在 Unity 2018 上。

感谢 Eureka@UWA 问答社区提供了回答

Assetbundle

Q:用 UWA 检测 AssetBundle 资源冗余时,发现有 17 个资源冗余,但是通过对比查询 Bundle 的 Manifest 文件,发现这些冗余的资源都会单独打包成一个 AssetBundle,并且没有存在于自己预设资源中,但是 UWA 给的结论是这份冗余的资源存在于他所在的各个预设当中,请问是怎么解?

A:我也是当初遇到的问题,Manifest 没有这个冗余,AssetBundle 加载进来,内存里你也没有发现这个冗余,调用 GetAllAssetNames 也看不到这个冗余的名字,但是如果调用 LoadAllAssets,就出现了这个冗余,非常神奇,藏的很隐秘。

原因:Rawimage 挂的 Texture,ParticleSystem 引用 UI 资源。
冗余的危害我就不说了。

解决方案:如果说尽量保证 Rawimage 的图和 Prefab 等资源打到一个 AssetBundle,这个有点难,也很累,排查起来比较困难。

我的解决方案:

1.除了 Background,禁止 Rawimage 挂 Texture,而说实话,我的 Background 都做了 RGBA 分离,所以 Rawimage 挂的是 Material,而 Rawiamge 不挂 Texture 是因为我们项目都是异步加载了的,尽量保证 Prefab 先出来,后面不重要的异步出来。

2.禁止粒子特效挂在到 UI 的 Prefab 上,并且写工具,禁止粒子特效的 Prefab 引用 UI 资源,由于粒子特效 ParticleSystem 描述文件缺失大,如果挂在 UI 上,还会造成 Prefab 可能上 M 数量级,影响加载速度,同时粒子特效和 UIPrefab 分离,也不会造成冗余。

感谢夏霖锐@UWA问答社区提供了回答

Addressable

Q:想做传统的那种,在进入游戏的时候统一加载更新,而不是目前这种,读取某个界面,就去服务器判断。
现在的问题是怎么让每一次加载的时候不去判断服务器,而在进入的时候判断全部更新。

A:可以在游戏启动的时候在一个专门的更新界面做更新,具体做法是先初始化,然后调用 GetDownloadSizeAsync 和 Addressables.DownloadDependenciesAsync 进行 AssetBundle 更新(Addressable 是以 AssetBundle 为最小更新单元的),这样就会将所有需要更新的 AssetBundle 缓存到本地了,下次用到这些资源就不用远程下载了。大致代码如下:

IEnumerator Start() 
{       

    //只要打包的时候不要将Disable  Catalog Update on Startup勾选上就行,这样初始化的时候会自动更新Catalog到最新
    yield return Addressables.InitializeAsync();

    IEnumerable<IResourceLocator> locators = Addressables.ResourceLocators;        
    List<object> keys = new List<object>();
    //暴力遍历所有的key
    foreach (var locator in locators)
    {            
        foreach(var key in locator.Keys)
        {
            keys.Add(key);
        }
    }

    var handle = Addressables.GetDownloadSizeAsync(keys);
    yield return handle;
    long downloadSize = handle.Result;

    if (downloadSize > 0)
    {
        yield return Addressables.DownloadDependenciesAsync(keys, Addressables.MergeMode.Union, true);                
    }        
}

在游戏过程中,Addressable 初始化以后,只要不调用 Addressables.CheckForCatalogUpdates 和 Addressables.UpdateCatalogs,内存中常驻的 Catalog 生成的映射表对象是不会发生改变的,就算把服务器的 Catalog 和资源更新了也不会影响客户端的运行。

感谢 Xuan@UWA 问答社区提供了回答

封面图来源于网络


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在 UWA 问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之 “石”,也能攻你之 “玉”。

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
UWA 学堂:edu.uwa4d.com
官方技术 QQ 群:793972859(原群已满员)


↙↙↙阅读原文可查看相关链接,并与作者交流