编码(Coding)
使用 .NET standards为基础,并在下方进行了更改
命名(Wording)
- 使用描述性的且准确的名称(即使这使得名称更长),注重可读性而不是简洁性
- 不要乱用首字母缩略词,仅使用公认标准的首字母缩写
例如:UI、IO
- 方法名(Method)应该是动词或动词短语
- 属性名(Property)应该是名词、名词短语或形容词
- 布尔属性(Boolean)应该是肯定短语。可以在布尔属性前加上"Is",“Has”,can"
例如:IsActive、CanJump
- 如果多个属性与同一项相关,使用项名称作为前缀并添加属性类型或角色
private Color _gameTitleColor
private String _gameTitleString
private TextMeshProUGUI _gameTitleText
- 如果名称不在固定列表中,避免使用数字作为名称
例如:animator1、animator2
而是说明两个属性之间的区别
例如:playerAnimator、enemyAnimator
拼写(Capitalization)
- 骆驼拼写法(camelCase):第一个词的首字母小写,后面每个词的首字母大写
- 帕斯卡拼写法(PascalCase):每个单词的首字母都是大写的。如果单词是由两个字母组成的首字母缩略词,则两个字母都要大写。如果单词是包含两个以上字母的首字母缩略词,则只有第一个字母大写
- 类、方法、枚举、名称空间、公共字段/属性使用PascalCase
例如:ClassName、GetValue
- 局部变量、方法参数使用camelCase
例如:previousValue mainUI
- 私有字段/属性使用camelCase,但以下划线开头
例如:_inputReader
- 常量全大写,用下划线分隔单词
例如:GRAVITY_AMOUNT
编程(Programming)
- 保持字段和方法为private,除非需要它们public
- 如果想在Inspector中显示字段,而不想让其他类访问这个变量,不要用public,使用private和特性[SerializeField]
注意:这样可能会得到警告"Field is never assigned to, will always have its default value",使用=default为字段指定默认值
- 尽量避免使用单例(Singletons)。尝试使用ScriptableObjects(1,2)来建立一个类似的、集中的、可以从多个对象中访问的类
- 声明变量时不要使用var,始终显式地编写它的类型
- 避免使用静态变量,如果你绝对需要他们,请确保它们与Fast Enter Play Mode兼容
- 不要在你的代码中使用硬编码的"魔法数字"
例如:角色移动xInput*0.035f,为什么用这个数字?请将这个数字存储在一个有明确名称的字段中——也许再加个注释说明为什么选择这个特殊数字
- 提交代码之前,删除所有没使用过的using命令
例如:using System
格式(Formatting)
- 使用空格来缩进代码,不要用Tab
- 花括号:如果内容为空,写在同一行。如果非空,每个占一行
public class EmptyBraces(){}
public class NonEmptyBraces
{
// ...
}
- 相互包含的逻辑单元需要缩进以表示层次关系
public void FunctionName()
{
if(somethingHappended)
{
// ...
}
}
注释(Comments)
- 重要:不要为了注释而注释。如果你认为任何人只要看一眼就能理解代码的作用,就不要添加注释,给变量、类、方法良好的名字,让他们解释自己!
- 使用行内注释为单独的代码行进行补充说明
- 在每一个类上都要写摘要,以描述类的目的。如果一个类可读性不高或者功能细节不直观时,可以选择性的在摘要中加入这些细节
/// <summary>
/// This class manages save data
/// </summary>
提示:在IDE中输入三个"/"符号,一般会自动生成摘要。看微软官方规范
- 在方法前写注释,解释它的功能,以防方法名不准确,或者添加其他重要的细节,可以用行内注释
/// <summary> This function does this... </summary>
public float CalculateBoundingBox(){ }
- 使用以//TODO:开头的注释来表示需要稍后完成的事情,这样你就不会忘记了
注意:这不是在鼓励你推送未完成的功能
- 不要写#region或者//--------这类注释
场景/层次结构(Scene/Hierarchy)
组织结构(Organisation)
- 在根(root)上创建空的GameObject并命名,创建视觉上的分隔符
例如:"— Camera —","— Environment —","— Lighting —"等
给这些分隔符添加"EditorOnly"标签,这样打包的时候就不会加入
- 可以使用空的GameObject作为容器,但不要只包含1-2个物体
- UI
- 尽可能使用同一个Canvas,只有在Canvas属性改变的时候才创建多个Canvas
- 每一个屏幕创建一个面板(Panel)
例如:一个设置标签和它的选项
- 用面板(Panel)作为容器,将UI元素进行分组
例如:一个设置标签和它的选项
面板能帮忙固定需要固定在一起的元素
例如:一些能量/物品UI在屏幕右下角
命名(Naming)
- 在GameObject命名中不要用空格
- 用PascalCase命名
例如:MainCharacter,DoorTrigger
- 如果仅用PascalCase命名会产生歧义,用下划线连接两个概念
例如:MainHall_ExitTrigger,BossMinion_AttackWaypoints
- 预制体(Prefabs):如果合理,可以重新命名实例
例如:一个Prefab Variant文件名称为"Protagonist_Scene1Variant",如果你只用它一次,可以直接重命名为"Protagonist"
项目文件(Project files)
命名(Naming)
- 与 Scene/Hierarchy 规则相同
- 同一个文件夹下,如果文件相关,使他们名称自然而然地归为一组
- 一般来说,名字要以该物体所属的事物作为前缀
例如:PlayerAnimationController、PlayerIdle、PlayerRun等
- 合理的情况下,可以使相似的对象保持在一起,即使他们属于不同事物,或者形容词导致他们分开
例如:在一个道具资产文件夹中,你可以用TableRound、TableRectangular来作为名称,这样它们就呆在一起,如果用RoundTable、RectangularTable,他们就不在一起了
- 避免在名称中使用文件类型
例如:用ShinyMetal代替ShinyMetalMaterial
文件夹(Folders)
- 在根目录中,将你的资源放在能够识别游戏区域/系统/位置的文件夹中,可以创建子文件夹来分隔不同类型的资产
- 场景总是放在Scenes文件夹中
- 不属于特定系统的脚本放在Scripts文件夹中,可以创建子文件夹来分类
- 总而言之:如果一个系统/功能只有脚本,那就在Scripts中创建一个文件夹。如果它有其他类型的资产,那么将该文件夹放在根目录中,并根据资产类型添加子文件夹。如果它有其它类型的资产,就把该文件夹放在根目录下,并按照资产类型添加子文件夹
┌── Art
│ ├── Characters
│ │ └── PigChef
│ │ ├── Materials
│ │ ├── Prefabs
│ │ └── Textures
│ ├── Environment
│ │ ├── Interiors
│ │ ├── Nature
│ │ │ ├── Materials
│ │ │ ├── Prefabs
│ │ │ └── Textures
│ │ └── Props
├── UI
│ ├── Materials
│ ├── Scripts
│ └── ScriptableObjects
├── InventorySystem
│ ├── Scripts
│ └── ScriptableObjects
├── Scenes
│ ├── Locations
│ └── Menus
└── Scripts
└── SceneManagementSystem