unity-csharp-scripting
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseUnity C# Scripting (MonoBehaviour)
Unity C# 脚本编写(MonoBehaviour)
Write correct, idiomatic gameplay scripts in Unity 6. Get the lifecycle, component
access, serialization, and coroutines right so behaviour is deterministic and the
Inspector stays useful. Targets Unity 6 (6000.0 LTS), C# / .NET Standard 2.1.
编写符合规范的Unity 6游戏玩法脚本。正确掌握生命周期、组件访问、序列化和协程,确保行为可预测且Inspector面板保持实用。目标版本为Unity 6 (6000.0 LTS),使用C# / .NET Standard 2.1。
When to use
使用场景
- Use when authoring or fixing a : choosing the right lifecycle callback, reading/caching components, exposing fields to the Inspector, or running timed logic with coroutines.
MonoBehaviour - Use when the project has files, an
*.csorAssembly-CSharp, and a*.asmdeffolder.ProjectSettings/
When not to use: moving rigidbodies / collision response → ; reading
player input → ; shared data assets / config → ;
Animator parameters → . This skill owns the script lifecycle and C#
plumbing, not those subsystems.
unity-physicsunity-input-systemunity-scriptableobjectsunity-animation- 当编写或修复脚本时使用:选择合适的生命周期回调、读取/缓存组件、向Inspector面板暴露字段,或使用协程执行定时逻辑。
MonoBehaviour - 当项目包含文件、
*.cs或Assembly-CSharp文件,以及*.asmdef文件夹时使用。ProjectSettings/
不适用场景:移动刚体/碰撞响应 → 请使用;读取玩家输入 → 请使用;共享数据资源/配置 → 请使用;Animator参数 → 请使用。本技能负责处理脚本生命周期与C#基础架构,而非上述子系统。
unity-physicsunity-input-systemunity-scriptableobjectsunity-animationCore workflow
核心工作流程
- Pick the callback by purpose, not habit. (cache references, runs once on load),
Awake(subscribe to events),OnEnable(init that depends on other objects'Start),Awake(per-frame logic/input polling),Update(physics),FixedUpdate(camera follow after movement),LateUpdate/OnDisable(unsubscribe/cleanup).OnDestroy - Cache component lookups in — never call
Awakeevery frame.GetComponent - Expose tunables with , not public fields, so other code can't mutate them but designers can edit them in the Inspector.
[SerializeField] private - Scale per-frame values by in
Time.deltaTime(andUpdatesemantics are automatic inTime.fixedDeltaTime).FixedUpdate - Use coroutines for time-sequenced logic (delays, tweens, "do X then wait then Y");
start them with and stop them deterministically.
StartCoroutine - Verify in Play mode: check the Console for null-reference exceptions, confirm values
in the Inspector update as expected, and watch the Profiler if is hot.
Update
- 根据用途选择回调,而非习惯。(缓存引用,加载时运行一次)、
Awake(订阅事件)、OnEnable(依赖其他对象Start完成的初始化)、Awake(每帧逻辑/输入轮询)、Update(物理相关)、FixedUpdate(移动后跟随相机)、LateUpdate/OnDisable(取消订阅/清理)。OnDestroy - 在中缓存组件查找结果 —— 绝不要每帧调用
Awake。GetComponent - 使用暴露可调参数,而非公共字段,这样其他代码无法修改它们,但设计师可以在Inspector面板中编辑。
[SerializeField] private - 在中按
Update缩放每帧数值(Time.deltaTime中FixedUpdate的语义是自动处理的)。Time.fixedDeltaTime - 使用协程处理时间序列逻辑(延迟、补间、“执行X然后等待再执行Y”);通过启动协程,并以可预测的方式停止它们。
StartCoroutine - 在Play模式中验证:检查控制台是否有空引用异常,确认Inspector面板中的值如预期更新,如果占用过高性能则查看Profiler。
Update
Patterns
模式示例
1. Lifecycle + cached components (the canonical skeleton)
1. 生命周期 + 缓存组件(标准框架)
csharp
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);
}
}csharp
using UnityEngine;
[RequireComponent(typeof(Rigidbody))] // 自动添加依赖,防止空引用
public class PlayerController : MonoBehaviour
{
[SerializeField] private float moveSpeed = 6f; // 可在Inspector中编辑,代码中为私有
private Rigidbody _rb; // 缓存,不每帧获取
private void Awake() => _rb = GetComponent<Rigidbody>(); // 加载时缓存一次
private void Update()
{
// 每帧执行的非物理操作。按deltaTime缩放以确保帧率无关。
transform.Rotate(0f, 90f * Time.deltaTime, 0f);
}
private void FixedUpdate()
{
// 物理操作应在此处执行(固定时间步长)。请查看unity-physics技能。
_rb.MovePosition(_rb.position + transform.forward * moveSpeed * Time.fixedDeltaTime);
}
}2. Safe component access with TryGetComponent
TryGetComponent2. 使用TryGetComponent
安全访问组件
TryGetComponentcsharp
// Avoids allocating a null and is clearer than GetComponent + null check.
if (other.TryGetComponent<Health>(out var health))
health.Apply(-10);csharp
// 避免分配空值,比GetComponent + 空值检查更清晰。
if (other.TryGetComponent<Health>(out var health))
health.Apply(-10);3. Serialization that shows up correctly in the Inspector
3. 在Inspector中正确显示的序列化
csharp
[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 Inspectorcsharp
[SerializeField, Range(0f, 1f)] private float volume = 0.8f; // 滑块
[SerializeField] private string playerName = "Hero"; // 私有但可序列化
[System.Serializable] // 普通类要序列化/显示必须添加此特性
public class Stats { public int hp = 100; public int mana = 50; }
[SerializeField] private Stats stats = new(); // Inspector中的嵌套类数据4. Coroutines for time-sequenced logic
4. 协程处理时间序列逻辑
csharp
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
}csharp
private void Start() => StartCoroutine(FlashThenHide());
private System.Collections.IEnumerator FlashThenHide()
{
yield return new WaitForSeconds(0.5f); // 等待0.5秒游戏时间
GetComponent<Renderer>().enabled = false;
yield return null; // 下一帧恢复执行
}Pitfalls
常见陷阱
- in
GetComponent— it searches every frame and tanks performance. Cache the reference inUpdate/Awake.Start - Physics in — moving a
Updatewith forces orRigidbodyoutsideMovePositioncauses jitter and timestep-dependent behaviour. Read input inFixedUpdate, apply physics inUpdate.FixedUpdate - Relying on order across objects —
Startruns after allStarts, but order amongAwakes is undefined. Do cross-object wiring inStart, self-setup inStart.Awake - fields just to show them in the Inspector — that also lets any script mutate them. Use
publicinstead.[SerializeField] private - allocates a string and is slower; use
gameObject.tag == "Enemy".gameObject.CompareTag("Enemy") - Coroutines stop when the GameObject is disabled — a disabled object's coroutines are
killed; re-in
StartCoroutineif it must survive toggling.OnEnable - never runs before
Update, but the firstStartcan run on the same frame asUpdate— guard against not-yet-initialised fields if you split setup oddly.Start
- 在中调用
Update—— 每帧都会搜索,严重影响性能。在GetComponent/Awake中缓存引用。Start - 在中处理物理 —— 在
Update之外使用力或FixedUpdate移动MovePosition会导致抖动和时间步长相关的异常行为。在Rigidbody中读取输入,在Update中应用物理。FixedUpdate - 依赖多个对象的执行顺序 ——
Start在所有Start执行后运行,但多个对象的Awake执行顺序未定义。跨对象连接在Start中完成,自设置在Start中完成。Awake - 仅为了在Inspector中显示而使用字段 —— 这会让任何脚本都能修改它们。请改用
public。[SerializeField] private - 使用—— 会分配字符串,速度较慢;请使用
gameObject.tag == "Enemy"。gameObject.CompareTag("Enemy") - GameObject禁用时协程会停止 —— 禁用对象的协程会被终止;如果需要在切换启用状态时继续运行,请在中重新调用
OnEnable。StartCoroutine - 永远不会在
Update之前运行,但第一次Start可能与Update在同一帧运行 —— 如果拆分设置逻辑不当,请防范未初始化的字段。Start
References
参考资料
- For the full event-execution-order table and advanced coroutine patterns (custom
, stopping by handle,
CustomYieldInstruction/WaitUntil), readWaitWhile.references/lifecycle-and-coroutines.md - Primary docs: Unity Manual "Event function execution order"
() and
https://docs.unity3d.com/Manual/execution-order.html.ScriptReference/MonoBehaviour
- 完整事件执行顺序表和高级协程模式(自定义、通过句柄停止、
CustomYieldInstruction/WaitUntil),请阅读WaitWhile。references/lifecycle-and-coroutines.md - 官方文档:Unity手册“事件函数执行顺序”()和
https://docs.unity3d.com/Manual/execution-order.html。ScriptReference/MonoBehaviour
Related skills
相关技能
- —
unity-physics, collisions, andRigidbodymotion.FixedUpdate - — reading player input into these scripts.
unity-input-system - — sharing data/config between scripts without singletons.
unity-scriptableobjects
- ——
unity-physics、碰撞和Rigidbody运动。FixedUpdate - —— 在这些脚本中读取玩家输入。
unity-input-system - —— 在脚本之间共享数据/配置,无需单例。
unity-scriptableobjects