Files
Vision/.agents/skills/unity-development-rules/SKILL.md
T
2026-10-14 14:46:24 +08:00

3.7 KiB
Raw Blame History

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);
}

边界:这条只约束游戏运行时代码。编辑器工具、一次性批处理脚本需要按结构查找节点时可以照常查找。

动画一律用 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 还没导入这个文件,控制台没报错不代表它编译通过。