踩坑合集

  • 按照我们的语言习惯,在表示小数时,用点号“.”表示小数点,用逗号“,”表示分位符,如1,111.1
    但在越南和一些欧洲国家如法国德国等则是反过来的,用逗号“,”表示小数点,用点号“.”表示分位符, 如1.111,1
    另外更特别的是波斯语中是用“/”表示小数点!
    因此,你在保存数字时或解析字符串时则需要注意该语言差导,否则会有意相不到的bug等着你。
    CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");或者.ToString(CultureInfo.InvariantCulture)简单处理可以这样统一语言环境。
  • 2023.02.27 00:00:00这种时间格式字符串在印尼等国家语言环境下DateTime.Parse(str)解析失败,类似上一条需要固定区域:
    DateTime.Parse(timeStr, System.Globalization.CultureInfo.InvariantCulture)
  • TextMeshPro中文显示会遇到只能显示一部分的情况,报错如下:
    UnassignedReferenceException: The variable m_AtlasTextures of TMP_FontAsset has not been assigned.
    You probably need to assign the m_AtlasTextures variable of the TMP_FontAsset script in the inspector.
    中文字符量大,一般使用的是动态字体,需要运行时动态生成多张文字图集:

     

     文字消失就是当默认的第一张图集被塞满了后生成第二张图时m_AtlasTextures为空出错而生成失败导致的。

     m_AtlasTexture首次运行时本身就为空,但如果ui上有用到该字体就会走到以上代码就会被初始化,所以多数人遇不到。
    而我们项目主要使用英文,中文是通过设置fallback字体来实现的,所以没有直接用到该字体也就不会被初始化。
    也好解决,在你第一个ui上增加引用就行,或者自己手动调用该属性来解决,或源代码中用m_AtlasTexture改为用属性atlasTexture也解决了,但改代码得从upm中移出来。
    期待Unity官方修复这个bug(我在官方论坛回复了问题原因,但并没有得到回应)。

  • C#调用Process StartInfo执行命令行时在Windows下需要在Arguments参数上命令前增加/c才能正确执行。
    而Mac上面则分情况,bash命令如ls、svn等则需要在命令前增加-c指令且需要把命令用引号包起来:-c "ls -l",如果仍然执行失败则需要再添加-l指令(脚本调起的可能为非交互式非登录Shell下的环境变量只有最基础的几个)来指定为当前用户的shell:-l -c "svn info";
    若是代码调用外部shell脚本失败,可考虑将脚本路径改为全路径,相对路径可能不行,仍有问题则可能也需要加上-l -c,如果仍然有问题,则.command脚本首行也需要通过i l指定shell:#!/bin/bash -ilex,对于e参数表示一旦出错,就退出当前的shell,x参数表示可以显示所执行的每一条命(x视情况是否需要)。
  • C#调用Process StartInfo执行命令行时获取的结果输出会乱码:

     指定输出编码格式可解决:

    p.StartInfo.StandardOutputEncoding = Encoding.UTF8;
    p.StartInfo.StandardErrorEncoding = Encoding.GetEncoding(CultureInfo.CurrentCulture.TextInfo.OEMCodePage);
    网上大部分都说设置UTF8即可,但自测发现UTF8只有在MAC苹果电脑上可以解决乱码问题,在windows电脑上寻常编码格式全都试过了都会出错,最后通过以上下面那行加粗代码动态获取编码格式才得以解决:

    故需要用宏将不同平台设置为不同的编码,StandardOutputEncoding和StandardErrorEncoding最好都同时设置为同样的编码格式

  • float Epsilon = 1e-10;该行shader代码在ipad 5和ipad mini 4机型上发现显示异常,有一些黑色块出现,而其他设备没有问题。应该是ipad部分机型硬件问题,不支持e这做写法
    解决办法即将1e-10改为0.0001,另外需要确保该变量定义需要在函数内部而不能在外部,如果需要在外部定义常量给多个函数共用则需要用#define宏定义。
  • 粒子在Prewarm勾上时,编辑器运行与非运行状态下在同一样的时间时效果不一样,即预热的那段时间会带来显示上的差异,ParticleSystem.Simulate()函数指定时间时可能跟你在编辑器制作时停留时间预览不一样,如果需要运行时跟编辑时一致,建议取消Prewarm。

  • 当有很多的2D UI图片要显示时可以考虑用UGUI的CavasRenderer手动传入SubMesh的方式来优化(必须同时挂上Canvas组件,否则会巨卡)。
    但底层限制了数量最多只能有8个子Mesh,当有大量子Mesh要显示时就只能转为普通3D的MeshRenderer来显示了,性能会好很多。
    当3D物体也需要被UGUI的Mask或者RectMask2D遮罩时会有问题,当MeshRenderer用UI相同的shader时:
    * 配合Mask组件使用时,即便Mesh上的材质指定为同被遮罩的UI元素一样的stencil值遮罩不正常,整个Mesh都会不可见,原因为UGUI在Mask功能渲染完毕后又会把stencil的值清空,你的Mesh读到的值就是错误的。需要自己手动指定遮罩区域的sencil值,等于需要自己实现Mask组件的相应功能,包括嵌套Mask的情况。
    * 配合RectMask2D组件使用时,需要手动传入Mesh上材质的_ClipRect裁剪区域坐标,如果在ScrollRect滑动列表中则还需要实时修改裁剪区域坐标,而UGUI传入的UI自身的相对坐标,将UI上能被正常裁剪的_ClipRect复制到Mesh上材质是有问题的,Mesh上需要传入的坐标为另一参考系(手动改值慢慢尝试发现类似世界坐标,明显比UI上的值小个数量级),未深入研究不清楚规律。
  • xLua调用Unity的动画类Animation时如果不生成代码则只能反射调用,结果部分函数如animation.GetClip()、animation.Stop()会找不到函数而出错,必须配置LuaGenConfig生成代码后调用才能成功。
  • Unity内播放视频文件最简单的方法就是使用VideoPlayer组件。
    坑1:同为mp4文件查看属性时也有h.264的说明,但其编码格式可能android机上播放不了(ios上可以)(不同视频编辑软件可能功能不一样也许默认导出的mp4也能播放,此处测试为Mac机上某软件有MPEG4/H.264/H.265三种选择)。
    解决办法:在导出视频时需要显式指定为h.264(推荐)或h.265(不推荐)(垃圾设备可能支持不好且视频宽高有限制不能超过2300多否则需要额外解码器支持)或者在Unity中将视频文件勾上Transcode进行转码(转码如果选择为高配置则文件大小可能会倍增)。
    坑2:在Android 9以下的设备不支持直接播放AssetBundle中的视频文件,报错:

    W/Unity: AndroidVideoMedia::OpenExtractor could not translate archive:/CAB-de617f9f2b6b7a4679af2e89406b6bab/CAB-de617f9f2b6b7a4679af2e89406b6bab.resource to local file. Make sure file exists, is on disk (not in memory) and not compressed.
    W/Unity: AndroidVideoMedia: Error opening extractor: -10004

    尝试过Unity中打AB包时选择Uncompress不压缩,且Android build.gradle文件中noCompress配置上所有.ab文件都不压缩,仍然播放不了。
    将视频文件放到StreamingAssets目录通过VideoPlayer.url使用,在低端Andorid设备上无法播放(不确定是否为Android 9以下,测试机型为Android 7)
    解决办法:视频文件直接放到Resources目录中,或者将视频文件从AB包中提取出来复制到其它缓存目录中(通过UnityWebRequset网络请求本地地址加载拷贝AB包或将视频文件后缀修改为.bytes直接加载AB包获得数据复制内容)。
    坑3:高分辨率(宽高为1080*2400)在低端Android机上播放不了(不确定是否为Android 9以下,测试机型为Android 7)。
    解决办法:修改原始视频文件高度(不清楚具体限制是多少),或者在Unity中将视频文件勾上Transcode进行转码,把Dimensions选择为3/4或更低(画质会有影响)。

  • lua侧加载及读取Excel配置表数据有多种实现,最简单的方式为数据档直接保存为.bytes二进制文件,使用lua protobuf库直接加载;另外则是生成对应的lua文件直接require之。
    当表数量多且部分表有几十M甚至更大时则需要考虑时间与空间的取舍:
    生成的Lua文件有几十M时,使用lua语言去加载解析lua文件则效率相当低,此时只能牺牲空间换取时间,使用bytes二进制是更优的方案,pb库是C语言实现,加载和解析都更快,但数据量大则必定lua的table巨多最后lua侧占用很多内存。
    其他大量的小配置文件则可以用时间换空间,当数据量少时用二进制文件读取的速度提升可能并不明显,而用lua文件保存数据则可以采用更优的生成算法优化lua table的生成:
     1 local defaults = {
     2   activityId = 2,
     3   aniType = 2,
     4   num = 1,
     5 }
     6 
     7 local duplicates0 = {
     8   t0 = {["type"] = 2,["id"] = 90053,["count"] = 1,},
     9   t1 = {["type"] = 2,["id"] = 90054,["count"] = 1,},
    10   t2 = {["type"] = 2,["id"] = 90095,["count"] = 1,},
    11   t3 = {["type"] = 2,["id"] = 90112,["count"] = 1,},
    12 }
    13 
    14 local duplicates1 = {
    15   t4 = {["eff"] = [=[]=],["width"] = 0.0,["height"] = 0.0,},
    16   t5 = {--[[1]]0.8,--[[2]]1.0,},
    17   t6 = {--[[1]]1.0,--[[2]]1.2,},
    18   t7 = {--[[1]]duplicates0.t0,},
    19   t8 = {--[[1]]0.8,--[[2]]1.2,},
    20   t9 = {--[[1]]duplicates0.t1,},
    21   t10 = {["eff"] = [=[Angel/eff_angel]=],["width"] = 456.922,["height"] = 553.171,},
    22   t11 = {--[[1]]0.5,--[[2]]0.8,},
    23   t12 = {--[[1]]1.0,--[[2]]1.0,},
    24   t13 = {--[[1]]duplicates0.t2,},
    25   t14 = {["eff"] = [=[Joker/eff_joker]=],["width"] = 456.922,["height"] = 553.171,},
    26   t15 = {--[[1]]duplicates0.t3,},
    27 }
    28 
    29 local duplicates2 = {
    30   t16 = {["refreshWeight"] = 1,["pic"] = duplicates1.t10,["rect"] = duplicates1.t4,["catchProb"] = 100.0,["num"] = 2,["size"] = duplicates1.t11,["transparent"] = duplicates1.t12,["reward"] = duplicates1.t13,},
    31   t17 = {["refreshWeight"] = 1,["pic"] = duplicates1.t10,["rect"] = duplicates1.t4,["catchProb"] = 80.0,["num"] = 3,["size"] = duplicates1.t11,["transparent"] = duplicates1.t12,["reward"] = duplicates1.t13,},
    32   t18 = {["refreshWeight"] = 1,["pic"] = duplicates1.t14,["rect"] = duplicates1.t4,["catchProb"] = 100.0,["num"] = 2,["size"] = duplicates1.t5,["transparent"] = duplicates1.t12,["reward"] = duplicates1.t15,},
    33   t19 = {["refreshWeight"] = 1,["pic"] = duplicates1.t14,["rect"] = duplicates1.t4,["catchProb"] = 80.0,["num"] = 3,["size"] = duplicates1.t5,["transparent"] = duplicates1.t12,["reward"] = duplicates1.t15,},
    34 }
    35 
    36 local duplicates3 = {
    37   t20 = {--[[1]]duplicates2.t16,--[[2]]duplicates2.t17,},
    38   t21 = {--[[1]]duplicates2.t18,--[[2]]duplicates2.t19,},
    39 }
    40 
    41 
    42 local raw =
    43 {
    44   PbMT(defaults, {
    45     ["id"] = 105,
    46     ["activityId"] = 1,
    47     ["type"] = {
    48       {
    49         ["refreshWeight"] = 1,
    50         ["pic"] = {
    51           ["eff"] = [=[ghost/eff_ghostH_5_ani]=],
    52           ["width"] = 292.637,
    53           ["height"] = 259.894,
    54         },
    55         ["rect"] = duplicates1.t4,
    56         ["catchProb"] = 70.0,
    57         ["num"] = 3,
    58         ["size"] = duplicates1.t8,
    59         ["transparent"] = duplicates1.t5,
    60         ["reward"] = duplicates1.t9,
    61       },
    62     },
    63     ["aniType"] = 1,
    64   }),
    65   PbMT(defaults, {
    66     ["id"] = 201,
    67     ["type"] = duplicates3.t20,
    68   }),
    69   PbMT(defaults, {
    70     ["id"] = 202,
    71     ["type"] = duplicates3.t20,
    72   }),
    73 ...
    View Code

    通过将出现最多的值作为默认值、复用同样数据的table可以积少成多节省不少内存,也可加快解析的速度。
    另外分享一下另一种优化,因为配置表中所有的字段是确定且不变的,可以改为不用key做键,直接使用proto里定义的数字,这样就少了大量的文本字段,数字连续时也变成了数组,大大降低的文本大小及运行时的内存大小,但是!每次读取都需要转换一次找到实际的key的id,当数据表量大时导致运行时的速度降低很多,只能放弃……示例如下:

  • Unity的图片选项中Alpha Source有些误导人,给人感觉是只要我选了None它就应该自动给我去掉alpha通道节省至少1/4的内存:

    然而实际该选项仅在ASTC格式下起作用:

    这可能就是为什么ASTC的命名中A写在括号中,它是可选的,但也只是对表现有效,图片不再有半透效果,实际内存占用并不能减少!
    其它格式则由格式本身带不带A通道决定了,与Alpha Source完全没有关系。
    综上,Alpha Source大多数情况下都是可以不用管的,仅当需要使用ASTC格式且图片本身就有透明像素在显示时需要去掉透明像素的情况,或者使用平台自动决定格式时。

  • UGUI上双指(三指及以上不触发点击)同时点击或者快速多次点击同一个按钮(或不同按钮)都会多次触发onClick事件!即便你在点击事件处理中立即打开了一个全屏UI阻挡点击也没有用(可能因为这多个点击事件是在同一帧触发,而UI表现层在当前帧设置后并不能立即生效),
    要解决事件并发需要在事件回调处理中增加多点触控的判断如:if ((Input.touchCount <= 1) clickCallback()
    不能使用IPointerClickHandler点击回调参数给的PointerEventData中的clickCount来判断点击次数,其只在电脑上即鼠标操作时有效,触摸屏下永远是1,而Input.touchCount在鼠标下一直是0在手机屏幕下为手指个数或连点次数。
  • 图片压缩格式经验总结:

    ASTC压缩比在不同图片下不一样,时高时低,在多数情况下画质显示效果好,无图尺寸要求,在极少数android低端机型上不支持,会自动使用RGBA32原画质显示,此时内存占用会很大;

    ETC2压缩比一般,显示效果较好,画质在少数情况优于ASTC,要求图的尺寸必须是4的倍数;

    CrunchedETC2压缩比高,画质在小图时较好,大图有些比ASTC更好有时更差,要求图的尺寸必须是4的倍数;

    内存占用多数情况下ASTC8会优于CrunchedETC2,ASTC4则会更高,不同情况不一样;

    总的来说画质和内存表现上不会有特别明显的差距,跟图片上本身像素的情况有关,但综合看来ASTC是更优的压缩格式。

    如果项目不需要支持少数低端机型,图片又不是超级多小图,建议无脑选择ASTC。

    有大量小图时则优先选择CrunchedETC2,其他大图使用ASTC,使用工具批量将图全部转为4倍大小。

    普通ETC2较少使用,除非嫌CrunchedETC2效果不好又需要支持全部低端机型。

  • 在打完AssetBundle包,之后的第一次运行unity(重加载域时)或者触发代码编译的时候会在Reload Script Assemblies卡特别久:

     第二次及以后就正常了不会再卡进度条。打AB包时使用的是upm里的库Scriptable Build Pipline,用原旧api打包则不会有这问题。
    解决办法:删掉Library/BuildCache整个文件夹。看起来是SBP库有bug,当缓存过多时会导致这个问题。

posted @ 2022-08-05 15:23  桫椤  阅读(1570)  评论(0编辑  收藏  举报