5.9 KiB
name, description
| name | description |
|---|---|
| unity-development-rules | Unity 开发规则(Unity Vision 项目)。在本项目里写或改 C# 脚本、预制体、场景时适用,包含节点引用接线等硬性约定。 |
Unity 开发规则
本项目的硬性约定。动手写脚本、改预制体或场景之前先对照这里。
节点引用必须在 Inspector / 预制体里指定,不能硬编码到代码
脚本要访问场景或预制体里的节点(Transform、Text、Image、其他组件……)时,一律用 [SerializeField] 字段,由 Inspector 或预制体把引用接好。
不允许——在代码里按名字 / 标签 / 路径找节点:
// ❌ 节点名字写死在代码里
target = transform.Find("FPS").GetComponent<TMP_Text>();
target = GameObject.Find("FPS").GetComponent<TMP_Text>();
foreach (var t in GetComponentsInChildren<TMP_Text>(true))
if (t.name == "FPS") return t;
允许:
[SerializeField] private TMP_Text target; // ✅ 引用由 Inspector / 预制体提供
为什么:节点改名或挪位置以后,硬编码的查找会静默失效——不报错、就是不工作;而且引用关系藏在代码里,看 Inspector 看不出到底接没接上。
引用为空时:不要写运行时兜底查找,直接报错,让接线问题第一时间暴露。
private void Awake()
{
if (target == null)
Debug.LogError("[Xxx] 没有指定 target,请在 Inspector 里拖入。", this);
}
边界:这条只约束游戏运行时代码。编辑器工具、一次性批处理脚本需要按结构查找节点时可以照常查找。
Inspector 里的字段名怎么显示成中文
[InspectorName] 管不了普通字段:Unity 6 的文档对这个特性写的是 "enum value declarations"(只讲枚举值),实测把 [InspectorName("...")] 加在 [SerializeField] 字段上,字段的 displayName 仍是英文原名。别用它来改字段标签。
想让字段在 Inspector 里显示中文,只有这几条路:
-
中文字段名(要精确控制标签时用这个)。C# 允许 Unicode 标识符,字段名写中文,Inspector 里就显示这个中文——编辑器不会给中文插空格、术语表也不会翻译它(实测
NicifyVariableName("可到达半径")→可到达半径)。改名前必须加[FormerlySerializedAs("旧名")]:Unity 按字段名反序列化,直接改名会清空 Inspector 里已经接好的引用。// 语义是「玩家可到达的半径」,Inspector 里就显示「可到达半径」 [Tooltip("玩家可到达的半径,单位米")] [FormerlySerializedAs("reachableRadius")] [SerializeField] private float 可到达半径 = 5f; -
自定义 Editor:
[CustomEditor(typeof(Xxx))]里EditorGUILayout.PropertyField(prop, new GUIContent("可到达半径"))。字段少又必须换标签时才用,字段一多就是维护负担。 -
不改标签,用
[Tooltip]补说明:字段名保持英文(项目现状),鼠标悬停能看到中文说明。字段名本身够清楚时,这条就够了。
中文名按「这个字段在这个项目里干什么」来定,不要直译英文名:表示玩家可到达的半径,就写「可到达半径」,不要写成「半径」或「可达半径值」——同一个 Inspector 里经常并列出现好几个半径 / 距离 / 目标,标签本身就得能分清谁是谁。
顺带一个坑:编辑器语言是中文时,Unity 会按内置术语表翻译常见字段名(prefab → 预制件、radius → 半径 之类),只覆盖常见词——字段名一旦不是标准词,标签就原样显示英文。所以 Inspector 上看到的中文未必写在代码里,别去 .cs 里搜。
动画一律用 Animator 播,不用 legacy 的 Animation 组件
要在物体上播放动画时,走 Animator(状态 / 触发器 / 参数):
[SerializeField] private Animator animator; // ✅ 引用由 Inspector / 预制体提供
不允许——用老的 Animation 组件播动画:
// ❌ legacy 的 Animation 组件
_animation = GetComponent<Animation>();
_animation.clip = someClip;
_animation.Play();
// ❌ 运行时自己补一个 Animation 组件
gameObject.AddComponent<Animation>();
为什么:项目统一一套动画播放方式,动画和程序看同一处。混用会让同一个物体上既有 Animator 又有 Animation,两边驱动同一批属性,播放互相打架、排查困难。
例外:用户明确说明这次要用 Animation 才用,且只限那一次改动。
只做用户点名要做的事
用户说改哪里就只改哪里。下面这些都算「没说过的事」,不要顺手做:
- 给预制体 / 物体加组件(尤其是为了让自己写的代码能跑起来而补一个组件)
- 加用户没提过的功能或容错(自动回收、时长兜底、默认值兜底……)
- 动用户已经定好的行为或时序(例如特效 / 动画的播放时机)
- 保存场景、保存预制体、改其它资源
不改就做不下去时,先说明「为什么必须动它」并问一句,确认后再动。
预制体资产存不下场景对象引用
预制体上的脚本要指向场景里的物体(玩家、UI、相机……)时,预制体资产里这个字段只能是空的, 必须在每个场景实例上各接一次;指向资源(预制体、Clip、材质)的字段才可以直接在预制体上设。
接的时候留意目标是不是「真正会移动 / 变化」的那个节点:玩家根节点不动、真正移动的是子节点时,要接子节点。
「编译干净」要先确认脚本真的被 Unity 导入
改完脚本后,确认对应的 *.cs.meta 已生成、类型能在编辑器程序集里查到,再看编译结果。
否则 Unity 还没导入这个文件,控制台没报错不代表它编译通过。