1)Addressable资源管理
2)Addressable热更新问题
3)不合理旧图集拆分红新的小图集
4)XLua中在Lua和C#传递自定义值类型
5)Toggle的onValueChanged如何正确移除某个匿名的监听html
这是第216篇UWA技术知识分享的推送。今天咱们继续为你们精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。缓存
UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)网络
Addressable
Q1:你们用Addressable管理资源,对于AssetsGroups的Bundle Mode:选用Pack Together好,仍是选用Pack Separately好?你们有什么好的建议吗?app
A:Pack Together是最简单的管理方式,可是适合打包后比较小的资源集,好比少许通用的Shader能够打包在一块儿。可是每每仍是Pack Separately用的比较多,我的以为Separately更容易管理。ide
其实具体如何选择要看咱们须要打包的资源如何分类。假设一个游戏的资源分出如下类型:玩家、怪物、NPC、地图、特效、音乐和通用资源等,那么从功能和管理的角度考虑,来对这些资源进行目录管理。函数
RemoteAssets |__Players (Group) | |__Player01 (拖入Group) | | |__Animations (做为SubAsset,不可修改,会被打包进Player01) | | |__Materials | | |__Textures | | |__Models | | |__Prefabs | |__Player02 |__Monsters | |__Common | |__Monster001 | |__Monster002 |__Maps |__Map001
工具不一样Group内则以更新为单位来考虑,好比版本2须要新加Monster003,版本4须要添Map002。天然应该按这些小分类作Bundle打包。测试
因而能够以大分类作Group,选择Pack Separately,以小分类的目录拖进Group做为AssetEntry,这样基本就能管理好了。而且通常每一个Bundle的大小也能控制在合理范围内。优化
可是分开打包可能由于各个包内资源引用到其余共用资源,形成重复打包。所以总体尺寸会大于Together。因而咱们能够在某个Group内创建一个Common的子目录,将这个Group内可能被共用的部分提出来打包。网站
另一部分资源好比UI,能够考虑纳入一个Group,而后选择按Label打包。按UI使用的界面和更新批次创建Label,咱们这个步骤是结合AssetGraph利用文件名自动生成Label来设置Group的。
一些通用资源能够单独创建Group,而后选择Pack Together。可是咱们依然是创建一个叫Common的Group,而后仍是选择Separately。
这个组里面添加各个资源目录:
Common |__ Fonts |__ Shaders |__ Materials
大体思路是这样,可是还会要结合各个项目的实际需求,功能分割,更新和运营要求来作设计。
Q2:目前比较奇怪的现象是用Pack Separately打出的包要比Pack Together的大不少。
另外对于Addressable咱们会有针对性地设置它的Group分组,好比按照功能、按照资源类型进行分组,若是全部资源都是Pack Together模式,那么Addressable会对应生成Group个数的Bundle文件,而后咱们利用Addressable的Analyze工具,进行冗余资源分析,自动分析出的Group资源,咱们仍是用Separately模式在分析一次?检验下是否还有冗余吗?
另外还有个想法:把全部资源Group进行Separately打包,而后再用Analyze分析工具进行冗余检查,和先用Together模式进行打包再分析冗余,这两种操做方式,分析出的结果会是同样的吗?
A:其实咱们基本不用Analyze工具,咱们尽可能做到全部资源的具体去向(打到那个具体包)都能清晰地管理和掌握,最多结合UWA的AssetBundle分析工具来找出冗余,而后手动来作移动和管理。只要每添加一个资源都能严格按照既定的规范来管理,目录分割清晰。导出和生成预制体的流程使用工具自动化,那么仍是很好管理的。
感谢黄程@UWA问答社区提供了回答
Addressable
Q1:Addressable打热更新资源的时候会生成一个新的资源在原来的目录下,和旧的资源在一个目录,那我是每次都要把这整个文件夹都上传到CDN上吗?有没有什么办法能把每次须要热更新的资源单独提取出来放在一个额外版本文件夹呢?
A:主要有如下几点:
- 只要传新的AssetBundle和Catalog。
- 若是不包含Hash,那么AssetBundle文件名同样的状况下会覆盖旧资源(可能存在CDN缓存问题)。
- 能够每次出更新包修改RemoteBuildPath,指向不一样目录。
- 继承一个BuildScriptPackedMode本身去实现一个Build脚本。
Addressables自己不对更新资源作版本号管理的,这个须要本身作。
Q2:麻烦问下,若是本身添加了版本控制,Addressable能够作到回退版本吗?例如已经使用版本2的Catalogs完成了更新,此时须要回退回版本1,用客户端版本2的Catalogs和服务端版本1的对比,能够再更回去吗?
A:没有试过,理论上能够,由于Addressable没有版本号概念,只对比Hash,不一样就认为有更新,至于新旧,它无论。
Q3:组设置里,有个Use Asset Bundle Crc.,若是勾选这个,那客户端的文件CRC校验失败(例如被修改器之类的改了),Addressable会怎么处理呢?看描述说,这个是本地文件和远程文件都起做用的,这里对于Load Path分别是本地和远程的组来讲,有什么不一样吗?
A:CRC检测失败,天然这个资源的载入就失败了,Addressable会提示错误。这个过程通常来讲至关于用记录在Catalog内的CRC对下载的Bundle作校验。这个和本地远程应该没多大关系,就算放在本地的包,其实也能够经过更新来作替换使用的。这个时候也是能够作CRC检验的。更细节的部分我也没有具体关注过,你也能够读一下源代码,看看具体怎么实现的。
感谢黄程@UWA问答社区提供了回答
Texture
Q:咱们这边有这样的一个问题:用的TexturePacker打出的图集有大量的无效区域(好久的老图集了)有没有什么办法能够将这些图集拆分一下(须要考虑材质的分割和从新引用)。
A1:若是还有TexturePacker的工程,那么将ForceSquared的勾去掉,这样就不会强制正方形贴图,会根据实际使用的尺寸进行缩减了。
若是没有原工程,那么能够解析导出的.tpsheet文件,都是文本形式的。好比:
不一样版本可能格式不一样,可是都是能够解析的。而后作个小工具就能够分解而且重组了。粗暴点直接修改也行。通常只要Sprite名字不变,那么使用TexturePacker的SDK应该不须要考虑材质的分割和从新引用。
感谢黄程@UWA问答社区提供了回答
A2:TP打图集后期想拆分很难了,包括Sprite更名字都麻烦。若是大家能保证每一个Sprite的名字都是惟一的,能够写脚本批量替换,不然就放弃。
感谢Walker@UWA问答社区提供了回答
A3:感受是有不太有自动化的方法,推荐是手写脚本批量替换,我倒以为Sprite名不定要惟一。
假设图集名字为a,新图集为b。
- 先遍历工程,找出对图集a引用的资源A等等。
- 将A引用的Sprite替换为b中对应的Sprite。
- 都替换完成后,再重复1,肯定a没有被引用。
还有1种状况是Atlas - Sprite对在代码中被使用,而非直接引用。那可能要定向查询配表信息/字符串常量了。
感谢cloud@UWA问答社区提供了回答
Script
Q:XLua在传递值类型的时候,可经过GCOptimizeAttribute来优化GC表现,经过AdditionalPropertiesAttribute来声明在C#和Lua之间作值传递时,看成字段来传递的属性(Property)。此外,对例如 UnityEngine.Vector3 的类型,Lua一侧在一些状况下可直接用Table传递,如:
local v = {x=1, y=2, z=3} + Vector3(4, 5, 6)
获得的V是个份量为五、七、9的Vector3。这个行为在生成Wrapper代码,或者以反射模式运行的时候,都是成立的。
可是我自定义的Struct类型,声明了上述Attribute,也生成了代码(包括CopyByValues等),相似行为只有生成Wrapper才能正确执行,在反射模式下传递的值都是0。请问为何?
Struct代码:
public struct SB { private int intField; private float floatField; private long longField; public static SB operator +(SB a, SB b) { return new SB { IntField = a.IntField + b.IntField, FloatField = a.FloatField + b.FloatField, LongField = a.LongField + b.LongField, }; } public int IntField { get => intField; set => intField = value; } public float FloatField { get => floatField; set => floatField = value; } public long LongField { get => longField; set => longField = value; } public override string ToString() { return $"int: {intField}, float: {floatField}, long: {longField}"; } public static SB Create(int intField, float floatField, long longField) { return new SB { IntField = intField, FloatField = floatField, LongField = longField, }; } }
Lua侧:
local SB = CS.SB local sb1 = SB.Create(1, 2.0, 3) local sb2 = SB.Create(2, 3.0, 4) Logger.LogWarningSafe(sb1 + sb2) Logger.LogWarningSafe(sb1 + {IntField=1, FloatField=2, LongField=3}) Logger.LogWarningSafe({IntField=1, FloatField=2, LongField=3} + sb1)
用反射模式运行的结果:
生成Wrapper代码后的运行结果:
后者运行结果正确。因此,使用AdditionalProperties,是否还须要作什么额外工做才能使得上述代码在反射模式和Wrapper模式下都能正确运行呢?
环境:Unity 2018.4.18f1,以及大约是2019年较早时候的xlua-framework。
A:你看一下AdditionalPropertiesAttribute的被引用状况就知道了,只在Generator里用到,反射模式下根本不判断这个的。
Vector3能够,是由于X、Y、Z都是Field。在反射方式下,只会用Field方式去尝试匹配(见ObjectCaster.cs 672行)。
感谢snuc@UWA问答社区提供了回答
Script
Q:以下述测试代码,OnDisable内的没法正确移除Test(), 其结果是屡次OnEnable后 onValueChanged时调用了不少次Test();
`public void OnEnable() { toggle.onValueChanged.AddListener(_ => Test()); }
public void OnDisable() { toggle.onValueChanged.RemoveListener(_ => Test()); } public void Test() { }`
A:RemoveListener的时候_ => Test()做为匿名函数是单独的实例,和Add的时候不是同一个,天然没法移除了。
`public void OnEnable() {
toggle.onValueChanged.AddListener(this.Test); } public void OnDisable() { toggle.onValueChanged.RemoveListener(this.Test); } public void Test() { }`试试:
`private Data _data;
private delegate void OnValueChangedDelegate;
private OnValueChangedDelegate onValueChanged;
public void OnEnable() { this.onValueChanged = ()=>{ OnValueChange_FileDelete(this.toggle, this._data); }; toggle.onValueChanged.AddListener(this.onValueChanged); }
public void OnDisable() { toggle.onValueChanged.RemoveListener(this.onValueChanged); }
public void OnValueChange_FileDelete(Toggle toggle, Data _data) {
}`
感谢黄程@UWA问答社区提供了回答
封面图来源于网络
今天的分享就到这里。固然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,咱们早已在UWA问答网站上准备了更多的技术话题等你一块儿来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。
官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
UWA学堂:edu.uwa4d.com 官方技术QQ群:793972859(原群已满员)