关于 unity-csharp-scripting
面向 Unity 6 开发者的 C# 脚本参考技能,用于编写或修复 MonoBehaviour。重点涵盖生命周期回调、组件访问、Inspector 序列化、协程及项目检查。
主要功能
- 01MonoBehaviour 生命周期指导
- 02缓存组件引用
- 03适用于 Inspector 的序列化
- 04使用协程编写定时逻辑
- 05.meta 与 GUID 项目检查
适用场景
- 01为游戏行为选择回调
- 02向设计师开放可调字段
- 03实现延迟和顺序动作
- 04文件变更后检查资源引用
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ gamedev-skills/ awesome-gamedev-agent-skills --skill unity-csharp-scripting安装后在 Claude Code 中输入/unity-csharp-scripting确认已加载。
附带文件references/lifecycle-and-coroutines.mdscripts/check_unity_project.py
详细介绍
Unity C# 脚本编写(MonoBehaviour)
在 Unity 6 中编写正确、符合惯例的游戏脚本。正确处理生命周期、组件访问、序列化和协程,让行为保持确定性,并让 Inspector 持续发挥作用。目标版本为 Unity 6.3 LTS (6000.3),使用 C# / .NET Standard 2.1。
适用场景
- 编写或修复
MonoBehaviour时使用:选择合适的生命周期回调、读取或缓存组件、向 Inspector 暴露字段,或使用协程运行定时逻辑。 - 项目包含
*.cs文件、Assembly-CSharp或*.asmdef,以及ProjectSettings/文件夹时使用。
不适用场景: 移动刚体 / 处理碰撞响应 → unity-physics;读取玩家输入 → unity-input-system;共享数据资源 / 配置 → unity-scriptableobjects;Animator 参数 → unity-animation。此技能负责脚本生命周期和 C# 接线逻辑,而非这些子系统。
核心工作流
- 根据用途选择回调,而不是依赖习惯。
Awake(缓存引用,在加载时运行一次)、OnEnable(订阅事件)、Start(依赖其他对象Awake的初始化)、Update(逐帧逻辑 / 输入轮询)、FixedUpdate(物理)、LateUpdate(在移动后跟随摄像机)、OnDisable/OnDestroy(取消订阅 / 清理)。 - 在
Awake中缓存组件查找结果——切勿每帧调用GetComponent。 - 使用
[SerializeField] private暴露可调参数,而不是使用公共字段,这样其他代码无法修改它们,但设计师可以在 Inspector 中编辑。 - 在
Update中,用Time.deltaTime缩放逐帧值(在FixedUpdate中会自动采用Time.fixedDeltaTime语义)。 - 使用协程编写按时间顺序执行的逻辑(延迟、补间、“执行 X,然后等待,再执行 Y”);使用
StartCoroutine启动,并以确定的方式停止。 - 在 Play 模式下验证:检查 Console 中是否有空引用异常,确认 Inspector 中的值是否按预期更新;如果
Update开销较高,则查看 Profiler。 - 完成前检查
.meta文件。 在 Editor 外创建、移动、重命名或删除脚本或资源时,始终同时移动文件及其.meta文件(新建.meta会生成新的 GUID,导致引用失效)。然后运行python scripts/check_unity_project.py <project-dir>(添加--json可输出机器可读结果),修复所有ERROR(重复或格式错误的 GUID、移动文件时未一并移动.meta、缺失的脚本引用),并重新运行,直到退出代码为 0。全新文件缺少.meta仅会产生警告;Unity 会在下次导入时创建该文件。请使用相对于此技能目录的脚本路径,或先解析已安装的技能路径。该脚本需要 Python 3.10+,不需要其他依赖,只会读取文本序列化资源,不能替代在 Unity 中打开项目。
模式
1. 生命周期与缓存组件(标准骨架)
using UnityEngine;
[RequireComponent(typeof(Rigidbody))] // auto-adds the dependency, prevents null refs
public class PlayerController : MonoBehaviour
{
[SerializeField] private float moveSpeed = 6f; // editable in Inspector, private in code
private Rigidbody _rb; // cached, not fetched per frame
private void Awake() => _rb = GetComponent<Rigidbody>(); // cache once on load
private void Update()
{
// Per-frame, non-physics work. Scale by deltaTime so it is frame-rate independent.
transform.Rotate(0f, 90f * Time.deltaTime, 0f);
}
private void FixedUpdate()
{
// Physics work belongs here (fixed timestep). See the unity-physics skill.
_rb.MovePosition(_rb.position + transform.forward * moveSpeed * Time.fixedDeltaTime);
}
}
2. 使用 TryGetComponent 安全访问组件
// Avoids allocating a null and is clearer than GetComponent + null check.
if (other.TryGetComponent<Health>(out var health))
health.Apply(-10);
3. 在 Inspector 中正确显示的序列化方式
[SerializeField, Range(0f, 1f)] private float volume = 0.8f; // slider
[SerializeField] private string playerName = "Hero"; // private but serialized
[System.Serializable] // REQUIRED for a plain class to serialize/show
public class Stats { public int hp = 100; public int mana = 50; }
[SerializeField] private Stats stats = new(); // nested struct-like data in the Inspector
4. 用协程编写按时间顺序执行的逻辑
private void Start() => StartCoroutine(FlashThenHide());
private System.Collections.IEnumerator FlashThenHide()
{
yield return new WaitForSeconds(0.5f); // wait half a second of game time
GetComponent<Renderer>().enabled = false;
yield return null; // resume next frame
}
常见陷阱
- 在
Update中调用GetComponent——每帧都会搜索,严重影响性能。在Awake/Start中缓存引用。 - 在
Update中处理物理——在FixedUpdate之外对Rigidbody施加力或调用MovePosition会导致抖动,且行为取决于时间步长。在Update中读取输入,在FixedUpdate中应用物理。 - 依赖不同对象的
Start执行顺序——所有对象的Awake都运行后,才会运行Start,但各个Start之间的顺序未定义。跨对象连接在Start中进行,自身设置在Awake中进行。 - 仅为了在 Inspector 中显示字段而将它们声明为
public——这样也会允许任何脚本修改这些字段。改用[SerializeField] private。 gameObject.tag == "Enemy"会分配字符串,速度也更慢;请使用gameObject.CompareTag("Enemy")。- 禁用 GameObject 时协程会停止——禁用对象的协程会被终止;如果协程必须在启用状态切换期间持续运行,请在
OnEnable中重新调用StartCoroutine。 Update不会在Start之前运行,但第一次Update可能与Start在同一帧运行——如果以不寻常的方式拆分设置流程,请防范尚未初始化的字段。
参考资料
- 有关完整的事件执行顺序表和高级协程模式(自定义
CustomYieldInstruction、按句柄停止、WaitUntil/WaitWhile),请阅读references/lifecycle-and-coroutines.md。 scripts/check_unity_project.py——只读.meta/GUID 和缺失脚本检查器;--help会列出所有检查项和退出代码。- 主要文档:Unity 手册“事件函数执行顺序”
(
https://docs.unity3d.com/Manual/execution-order.html)以及ScriptReference/MonoBehaviour。
相关技能
unity-physics——Rigidbody、碰撞和FixedUpdate运动。unity-input-system——将玩家输入读入这些脚本。unity-scriptableobjects——在脚本间共享数据/配置,无需使用单例。
评论
支持 Markdown