mcpField
U
unity-csharp-scripting

unity-csharp-scripting

github.com/josiahsiegel开发6096 次安装20 周前更新
代码仓库

关于 unity-csharp-scripting

面向 Unity 开发者的 C# 脚本参考,涵盖生命周期、物理、动画、音频、序列化、设计模式及 ECS/DOTS,并提供速查内容和详细示例索引。

主要功能

  1. 01MonoBehaviour 生命周期指导
  2. 02物理与碰撞 API
  3. 03动画和音频脚本
  4. 04序列化与设计模式
  5. 05ECS/DOTS 概念

适用场景

  1. 01选择 Unity 生命周期回调
  2. 02实现物理与碰撞行为
  3. 03组织低耦合的游戏系统

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill unity-csharp-scripting

安装后在 Claude Code 中输入/unity-csharp-scripting确认已加载。

附带文件references/design-patterns.mdreferences/physics-animation-audio.md

详细介绍

Unity C# 脚本模式

概述

Unity 开发的核心 C# 脚本参考。涵盖 MonoBehaviour 生命周期、物理与碰撞 API、动画脚本、音频、导航、常见设计模式、序列化,以及 ECS/DOTS 编码模式。

MonoBehaviour 生命周期

执行顺序
Awake() -> OnEnable() -> Start() -> FixedUpdate() -> Update() -> LateUpdate() -> OnDisable() -> OnDestroy()
方法调用时机用途
Awake()对象实例化时调用一次(在 Start 之前)自我初始化、缓存引用
OnEnable()每次对象变为活动状态时调用订阅事件、重置状态
Start()首次 Update 之前调用一次(所有 Awake 执行之后)跨对象初始化
FixedUpdate()固定时间步长(默认为 0.02s)物理、Rigidbody 移动
Update()每帧调用输入、非物理逻辑
LateUpdate()所有 Update 调用之后相机跟随、移动后调整
OnDisable()对象停用时调用取消订阅事件、保存状态
OnDestroy()对象销毁时调用最终清理、释放资源
关键规则
  • 即使组件已禁用,Awake 也会运行(但 GameObject 已禁用时不会)
  • 切勿依赖脚本之间的 Awake/Start 顺序——请使用 [DefaultExecutionOrder(N)] 或 Script Execution Order 设置
  • 使用 OnValidate() 在编辑器中验证序列化字段

协程与异步

协程
IEnumerator SpawnWaves(int count, float delay)
{
    for (int i = 0; i < count; i++)
    {
        SpawnEnemy();
        yield return new WaitForSeconds(delay);
    }
}
// Start: Coroutine handle = StartCoroutine(SpawnWaves(5, 1f));
// Stop: StopCoroutine(handle); or StopAllCoroutines();
Yield 指令行为
yield return null等待一帧
yield return new WaitForSeconds(t)等待 t 秒(受 timeScale 影响)
yield return new WaitForSecondsRealtime(t)使用非缩放时间
yield return new WaitForFixedUpdate()等待下一次 FixedUpdate
yield return new WaitForEndOfFrame()等待渲染完成
yield return new WaitUntil(() => condition)等待谓词为 true
yield return StartCoroutine(other)等待嵌套协程
Async/Await(Unity 6+ / UniTask)

对于 Unity 2023+/Unity 6,Awaitable 已内置。较旧版本请使用 UniTask。

async Awaitable LoadLevelAsync(string sceneName)
{
    await Awaitable.WaitForSecondsAsync(1f);
    var op = SceneManager.LoadSceneAsync(sceneName);
    while (!op.isDone)
    {
        progressBar.value = op.progress;
        await Awaitable.NextFrameAsync();
    }
}

事件与委托

事件模式(推荐)
// Publisher
public class Health : MonoBehaviour
{
    public event System.Action<float> OnDamaged;  // event keyword prevents external invocation
    public event System.Action OnDeath;

    public void TakeDamage(float amount)
    {
        currentHealth -= amount;
        OnDamaged?.Invoke(amount);
        if (currentHealth <= 0) OnDeath?.Invoke();
    }
}

// Subscriber
void OnEnable() => health.OnDamaged += HandleDamage;
void OnDisable() => health.OnDamaged -= HandleDamage;
void HandleDamage(float amount) => /* react */;
ScriptableObject 事件通道

无需直接引用即可解耦系统。将 GameEvent 创建为 ScriptableObject 资源,由发布者调用,并通过 GameEventListener MonoBehaviour 让订阅者监听。完整实现请参阅 references/design-patterns.md。

物理 API 速查

Rigidbody 移动(3D)
任务方法位置
持续施力rb.AddForce(dir * force)FixedUpdate
瞬时冲量rb.AddForce(dir * force, ForceMode.Impulse)FixedUpdate
直接设置速度rb.linearVelocity = dir * speedFixedUpdate
运动学移动rb.MovePosition(target)FixedUpdate
旋转rb.MoveRotation(targetRot)FixedUpdate

注意:在 Unity 6 中,Rigidbody.velocity 已重命名为 Rigidbody.linearVelocity。

射线检测
if (Physics.Raycast(origin, direction, out RaycastHit hit, maxDistance, layerMask))
{
    Debug.Log($"Hit {hit.collider.name} at {hit.point}");
}
// Use Physics.RaycastAll or Physics.RaycastNonAlloc for multiple hits
// 2D: Physics2D.Raycast, Physics2D.OverlapCircle, etc.
碰撞与触发器
回调要求用途
OnCollisionEnter/Stay/Exit双方都有碰撞体,且至少一方有 Rigidbody,isTrigger=false物理碰撞
OnTriggerEnter/Stay/Exit一方的碰撞体设置了 isTrigger=true,且至少一方有 Rigidbody区域、拾取物、检测

始终使用 CompareTag("Enemy"),而不是 other.tag == "Enemy"(避免 GC 分配)。

动画脚本

[RequireComponent(typeof(Animator))]
public class CharacterAnimation : MonoBehaviour
{
    static readonly int SpeedHash = Animator.StringToHash("Speed");
    static readonly int JumpTrigger = Animator.StringToHash("Jump");
    Animator _anim;

    void Awake() => _anim = GetComponent<Animator>();
    void Update()
    {
        _anim.SetFloat(SpeedHash, moveSpeed);
        if (jumped) _anim.SetTrigger(JumpTrigger);
    }
}

将 Animator.StringToHash 的结果缓存为 static readonly 字段,以避免每帧进行哈希计算。使用 Animation Events 实现与游戏进程时间同步的回调(脚步声、命中帧)。对于 IK,请使用 SetIKPosition/Rotation/Weight 实现 OnAnimatorIK(int layerIndex)。

音频速查

[RequireComponent(typeof(AudioSource))]
public class SFXPlayer : MonoBehaviour
{
    [SerializeField] AudioClip[] clips;
    AudioSource _source;
    void Awake() => _source = GetComponent<AudioSource>();
    public void PlayRandom() => _source.PlayOneShot(clips[Random.Range(0, clips.Length)]);
}

使用 AudioSource.PlayOneShot() 播放可重叠的音效。使用带有公开参数的 AudioMixer 控制音量。使用快照实现状态切换(战斗与探索)。

序列化

类型已序列化备注
public 字段是在 Inspector 中可见
[SerializeField] private是首选方案——保持封装性
[HideInInspector] public是,隐藏已序列化,但不会显示
[NonSerialized] public否不参与序列化
属性否Unity 从不序列化属性
字典否使用序列化列表并重建,或使用 Odin/SerializedDictionary
接口否使用抽象 ScriptableObject 或 SerializeReference

使用 [SerializeReference] 对接口和抽象类型进行多态序列化。

常见设计模式

模式适用场景方法
单例全局管理器(Audio、GameState)基于 ScriptableObject 或延迟初始化的 MonoBehaviour
观察者解耦通信C# 事件或 SO 事件通道
命令输入/撤销系统命令接口 + 历史记录栈
状态机AI、玩家状态枚举 + switch,或基于类的状态
对象池子弹、粒子、敌人使用预实例化对象的 Queue
服务定位器可测试的全局访问使用接口键的静态注册表

如需查看详细实现和代码示例,请参阅 references/design-patterns.md。

ECS/DOTS 快速参考

概念作用
Entity轻量级 ID(无 MonoBehaviour)
IComponentData实体上的纯数据结构体
SystemBase / ISystem基于组件查询运行的逻辑
EntityQuery按组件集合筛选实体
Jobs (IJobEntity)多线程系统
Burst CompilerSIMD 优化的原生代码

如需了解 ECS 架构模式和迁移指南,请参阅 references/design-patterns.md。

其他资源

参考文件
  • references/design-patterns.md —— 单例、观察者、命令、状态机、对象池、服务定位器和 ECS 模式的完整实现
  • references/physics-animation-audio.md —— 详细的物理设置(2D 和 3D)、高级动画(混合树、IK、根运动、Animation Rigging)和音频架构

评论

支持 Markdown