Unity游戏中的一些规范和优化建议

一.代码规范和建议

  1. 避免Update LateUpdate等函数内频繁的GC Alloc,避免在Update和LateUpdate内有以下操作:

  2. 调用GetComponet()

  3. 调用FindObjectsOfType()

  4. 使用GameObject.Tag和GameObject.Name

  5. 等等其他有堆内存分配的操作

  6. 避免频繁调用ToString()分配内存

  7. 避免OnGUI的调用

  8. 禁止使用Debug.Log打印log,用框架中的LogManager统一管理

  9. 避免使用枚举或struct做key进行字典查找(除非使用定制的comparer)他们的GetHashCode都有装箱操作,每次调用TryGetValue查找都会有内存分配.

  10. 在使用协程时尽量复用WaitXXX对象,而不是每次分配

  11. 频繁创建和更新的字符串尽量缓存,比如CD时间等

  12. 尽量避免dict.Values操作,直接遍历取Values即可

  13. 使用CompareTag代替GameObject.Tag

  14. 用RayCastNoAlloc替换RayCastAll

  15. 用yield return null 代替 yield reture 0

  16. 如果文件中不需要Update或Start函数等,删掉对应的空函数

  17. 尽量少用lambda,创建带upvalue的lambda对象会产生124B的GC,禁止在Update或for循环中使用

  18. 使用数组的数组,而不是多维数组。如int[i][j]的数组的数代替int[i,j]的多维数组

  19. 尽可能避免使用携程

  20. 禁止使用接受字符串参数的GetComponent等类似函数的重载方法,使用泛型类型的

  21. 代码中需要访问到 Transform 组件的位置数据时, 尽可能使用 localPosition 代替对 position 属性的访问. localPosition存储在transform中,访问该值时,Unity会直接将其返回,而position在每次访问时都会重新计算,如果要经常获取position,可以将其缓存起来。

  22. 避免使用LINQ表达式,部分功能无法在某些平台上使用,会分配大量GC Alloc。

  23. 禁止高频的字符串拼接. 如无法避免, 必须使用 StringBuilder 代替 "+" 操作符进行字符串拼接.

  24. Delegate 回调方法必须适时的解除注册, 否则回调方法所属的对象会一直有引用计数, 继而引起该对象所引用的资源无法得到释放.

  25. 尽量避免使用 Reflection(反射).

  26. 尽量避免使用可变参数(param object[] args), 避免装箱拆箱.

  27. 简单条件判断尽量使用三目运算符: b?x:y.

  28. 注意 List 等容器常用接口的复杂度, 尽量从尾部移除/批量移除(RemoveRange)等.

  29. 在频繁查询数据列表时, 建议使用 HashSet/HashTable 查找时间复杂度低的数据结构, 避免使用 List.

  30. 尽可能为快速产生和消灭的大量对象建立缓冲池.

  31. 尽可能将类或函数声明为 sealed, IL2CPP 会对 sealed 的类或函数进行优化, 变虚函数调用为直接函数调用.

  32. 尽量减少new的次数,预分配/成员变量替代临时new变量等.

  33. 最快的空串比较方法:最快的方法是str.Length == 0其次是str == String.Empty或str == "" 注:C#在编译时会将程序集中声明的所有字符串常量放到保留池中(intern pool),相同常量不会重复分配。(指的是这个"")

  34. 减少Find方法使用。Find()方法会遍历内存中的每个GameObject和组件,随着项目规模的扩张,它的开销将会越来越大。不要频繁的使用Find()和与其类似的方法,可以考虑在Inspector中设置对对象的引用,或者创建一个专门用于管理需要搜索的对象的引用的脚本。

  35. 避免使用Camera.main。 Camera.main 因此遭遇了和 Find() 一样的问题:在内存中搜索了所有的 GameObjects 和 Components,这个使用可能会消耗大。

  36. 尝试使用sqrMagnitude(即magnitude的平方)替代magnitude,减少开平方操作。

  37. 尽量少用模运算和除法运算,比如a/5f,要写成a*0.2f。

  38. 尽量避免在运行时为Transforms重新设置parent。Unity对于在同一个parent下的所有Transforms,内存排布是连续的类似动态数组,运行时重新设置parent可能会导致数组重新分配

  39. 变量和字段如果可以声明为const应该总是被声明为const,如果无法使用const,尝试使用readonly

二.其他规范和建议

  1. 禁止非图集贴图资源不合理的留白. 会影响 UGUI 运行时自动合批.

  2. 资源设置 UI 的贴图资源禁止勾选 Generate Mip Maps.

  3. 禁止使用修改 Alpha 值的方式来隐藏界面.

  4. 尽可能降低 Release 版中图集留白, 提高贴图利用率.

  5. 建议同一 Canvas 中使用到的图集数量控制在三个以内.

  6. 建立合理规划公共图集. 在内存占用/加载频度/引用复杂度之间确定合理的平衡点.

  7. 禁止匿名 GrabPass. 如需使用到 GrabPass 必须命名并尽可能复用.

  8. Shader中尽可能减少多 Pass 渲染, 除非必须这么做.

  9. 尽可能降低 Release 版中 Shader 中的 Keyword 数量.

  10. 尽可能降低 SkinnedMeshRenderer 组件数量.

  11. 禁止逐帧直接使用名称对 Shader Uniform 量进行更新

  12. 尽量避免在 Shader 中使用复杂的计算如: pow/sin/cos/tan/log 等.

  13. 建议在 Shader 中采用预混合或实时混合纹理的方式代替实时地多次纹理采样

  14. 移动平台的 Shader 编码一定要考虑数据精度(float/half/fixed)的合理使用.

  15. 应尽可能减少每帧 Material.GetXX/Material.SetXX的次数, 比如把多个 uniform half 变量合并为 uniform half4.

  16. 尽可能避免将 Animator 的 Culling Mode 属性设置为 Always, 对于不使用 RootMotion 的项目建议选择 CullCompletely.

  17. 尽可能避免使用物理引擎. 建议自行编码模拟物理效果

  18. 使用物理模块的游戏, 建议在 PhysicsManager 中设置矩阵, 会有较大的性能提升

  19. 如使用第三方音频插件, 需禁用 FMOD 模块(Edit -> Project Settings -> Audio -> Disable -> UnityAudio).

  20. 若不需要立体音效, 音频导入设置需勾选 Force to Mono(注: 制作音频时就应该制作单通道的.)

  21. 音频格式: iOS平台一般使用 mp3, Android平台一般使用 ogg.

  22. 无需由逻辑代码访问的渲染资源禁止勾选 Read/Write Enabled, 如网格和图片.

  23. 导入蒙皮网格模型时建议勾选 Optimize GameObject 优化选项, 可极大地降低骨骼层次复杂度, 优化 CPU 性能.

  24. 无动作模型资源必须将 Animation Type 设置为 None, 否则会导致游戏对象挂在不必要的动画脚本, 大量的话会严重影响 CPU 性能.

  25. 导入的模型如果无需用到法线和切线, 必须将导入设置的 Normals 和 Tangents 选项设置为 None.

  26. 导入的模型如果无需参与Unity Lightmap 烘焙, 必须将导入设置的 Generate Lightmap UVs 选项设置为 None.

  27. 禁止在 Release 版中存在任何 OnGUI 相关代码

  28. 禁止在 Release 版中存在任何日常调试相关的 UnityEngine.DeBug 类日志输出

  29. 禁止在 Release 版中开启 "Development Build" 和 "Script Debugging" 选项

  30. 在发布时必须将游戏锁定至合适的帧率(建议 30/60 帧)

  31. 禁止在 Release 版中使用引擎提供的 SendMessage 方法.

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值