shzlq 发表于 2023-6-2 18:25

在Unity写代码时有什么需要注意的坑吗?

在Unity写代码时有什么需要注意的坑吗?

上帝也疯狂 发表于 2023-6-2 18:25

作为一名Unity程序员,编写高质量的代码是至关重要的。
为了确保代码的可读性、可维护性和可扩展性,Unity程序员需要遵守一定的编码规范。本文将介绍一些常见的Unity编码规范,并给出示例。
一、命名规范
命名规范是编码规范中最基本的一部分。良好的命名规范可以使代码更易于阅读和理解。下面是一些常见的命名规范:

[*]变量和函数名应该使用有意义的名称。避免使用单个字母或缩写。
例如,使用“health”代替“hp”。

[*]变量名应该以小写字母开头,使用驼峰命名法。
例如,使用“playerHealth”代替“player_health”。

[*]函数名应该以动词开头,使用驼峰命名法。
例如,使用“UpdateHealth”代替“healthUpdate”。

[*]常量名应该全部大写,使用下划线分隔单词。
例如,使用“MAX_HEALTH”代替“maxHealth”。

[*]类名应该使用大写字母开头,使用驼峰命名法。
例如,使用“PlayerController”代替“player_controller”。
二、代码格式规范
代码格式规范可以使代码更易于阅读和理解。下面是一些常见的代码格式规范:

[*]使用缩进使代码更易于阅读。
例如,使用四个空格缩进代替制表符缩进。

[*]使用空格使代码更易于阅读。
例如,在运算符两侧使用空格。

[*]使用大括号使代码更易于阅读。
例如,在if语句中使用大括号包含代码块。

[*]适当的注释可以使代码更易于理解。
例如,在代码的关键部分添加注释。
三、性能规范
性能规范可以帮助Unity程序员编写高效的代码。下面是一些常见的性能规范:

[*]尽量避免使用字符串拼接。
例如,使用StringBuilder代替字符串拼接。

[*]避免使用过多的foreach循环。
例如,使用for循环代替foreach循环。

[*]避免使用过多的try-catch块。
例如,使用if语句代替try-catch块。

[*]避免在Update函数中创建过多的对象。
例如,将对象的创建放在Start函数中。
四、示例
下面是一个示例代码,演示了如何遵守上述的编码规范:

public class PlayerController : MonoBehaviour
{
    private int playerHealth = 100;
    private const int MAX_HEALTH = 100;

    private void Start()
    {
      // 初始化玩家
      InitializePlayer();
    }

    private void Update()
    {
      // 更新玩家生命值
      UpdateHealth();
    }

    private void InitializePlayer()
    {
      // 初始化玩家生命值
      playerHealth = MAX_HEALTH;
    }

    private void UpdateHealth()
    {
      // 更新玩家生命值
      playerHealth -= 1;
    }
}
在这个示例代码中,我们遵循了命名规范、代码格式规范和性能规范。变量和函数名使用有意义的名称,使用驼峰命名法。使用缩进和空格使代码更易于阅读。避免使用字符串拼接、过多的foreach循环和try-catch块,以提高代码的性能。
总结
编写高质量的Unity代码是一项艰巨的任务。遵循编码规范可以使代码更易于阅读、理解、维护和扩展。本文介绍了一些常见的Unity编码规范,并给出了示例代码。
Unity程序员应该始终遵循这些编码规范,以确保代码的质量和性能。
欢迎加入我的简介游戏开发交流群

o0runner 发表于 2023-6-2 18:26

订阅事件注意取消订阅

zxdxzh 发表于 2023-6-2 18:27

减少循环的调用


[*]上图最上方的代码是有一些问题的,假如代码中的myArray代表了100个敌人单位,那么这个循环不管是否满足条件,都至少要执行100次循环,而且后面还有100条的if判断语句
[*]上图最下方的代码对这个循环进行了优化,在进行循环之前先判断是否满足条件,这样就只有当条件满足时才需要执行里面的循环,如果条件不满足,循环就不用执行
[*]优化后的代码在条件不满足时只需要执行一条语句,条件满足时才要执行循环语句,而未优化的代码不管条件是否满足都需要执行循环语句并进行if判断,它们的编程效率差异显而易见
仅在改变时更新显示


[*]如果想要在Unity里对游戏场景或者游戏角色做持续更新,很多同学都会把功能写在Update函数里,比如显示当前的得分,上图最上方代码中的DisplayScore就是在游戏中显示得分的函数,要在游戏中显示当前得分就要不停调用DisplayScore函数
[*]这里就会有一些问题:“在当前目前的游戏得分没有改变时,也要不停更新数值显示”,这是不是有些浪费呢?这个问题的解决方法很简单

[*]当得分发生变化时再调用增加得分的语句,或者直接把显示得分的语句放在增加得分函数里(如果最下方的代码)
[*]比如游戏里面的玩家增加了十分,那么我就调用增加得分的函数增加十分并调用Unity里的文本组件显示更新以后的得分

增加代码更新的延时


[*]Unity默认一秒钟更新60帧画面,也就说一秒钟会执行更新函数60次,一些非常消耗性能代码如果每一帧都去执行那么它对系统运行的开销是非常大的,假设非常耗时的代码每执行一次需要消耗10毫秒,那么60帧画面就需要用600毫秒,CPU一秒钟也只有1000毫秒的运算时间
[*]如果游戏里还有其他的Update,那么它们的运行时间可能会超过1000毫秒,从而导致电脑或手机发热、卡顿
[*]现在我们知道了卡顿是由于程序中的一个或者多个功能叠加起来运行的时间太长了,造成CPU运算不能在给定的时间内运算完,那么应该怎么优化呢?

[*]优化方法叫做延时执行,或者分帧执行,在上图最下方的代码中我设置了运行间隔是3,也就是说这个操作每隔3帧执行一次,Update里的Time.frameCount代表当前游戏运行了多少帧,画面的帧数是从0开始一直往上增加,直到游戏运行结束为止
[*]用当前运行的总帧数除以运行间隔,如果是等于0,就执行这个非常耗时的操作

[*]这样就能减轻耗时操作运行的频率,也间接提高了运算效率,但是这样也会使游戏运算的次数减少,假设这个耗时操作是一个怪物的人工智能,如果它每3帧运行1次,那么这个怪物在做一些反应时可能会有3帧的延迟


[*]分帧执行的方案是可以优化的,比如每3帧执行一次耗时功能,那么我就可以控制第一个耗时操作在第0、3、6、9这几帧执行,另外一个耗时操作则在第1、4、7帧执行,这样就实现了把3个耗时的操作分到3帧里来分担压力的效果
在初始化时获取并缓存组件


[*]上图最上方的代码在游戏运行时会不断调用GetComponent来访问渲染器组件,并将渲染器作为参数调用来一个方法,这是一个耗时操作,如果你开发的是千人同屏或者万人同屏的游戏,每一个对象都有一个GetComponent,那么一万个对象在一帧画面里就要获取一万次渲染器,即使没有执行操作也消耗了许多性能,这完全是没有必要的

[*]因为游戏对象上的渲染器组件在获取一次后就不会被移除,所以根本不需要在每一帧游戏画面更新时获取一次,可以在脚本的Start方法里定义用于储存渲染器的成员,并在Start方法里通过GetComponent获取渲染器
[*]Start方法只在对象初始化时执行一次,这样就达到了只有一次GetComponent的效果,在游戏运行时就可以不停的对渲染器做各种各样的操作

[*]一些游戏公司在进行代码审核或者写编程规范时都会要求必须在启动时把所有的组件缓存起来,尽量避免游戏在的Update时不停获取组件
更多代码优化方法可以参考下方完整视频
http://pic1.zhimg.com/v2-6581c71e14c9369512de1b2693f38ac5.jpg?source=382ee89a
通过建立代码规范优化程序性能
https://www.zhihu.com/video/1536434213183737856
页: [1]
查看完整版本: 在Unity写代码时有什么需要注意的坑吗?