Unity Term Book
核心与架构

Component

Component 是挂在 GameObject 上的独立构建块,每个组件只定义一块行为。Unity 提倡组合(Composition)而非深层继承:把 Rigidbody、Collider、脚本等模块拼在一起。学会拆分大脚本、缓存 GetComponent 引用,是写出可维护、可复用 Unity 代码的关键技能。

想象一下...

Component 就像赛车的升级模块。底盘(GameObject)本身什么也做不了——但装上引擎(Rigidbody)、轮子(Collider)、方向盘(Script)和车灯(Light)后,车才有完整行为。每个模块彼此独立:拆掉车灯,引擎照样运转。

概念详解

Component 是 Unity 架构的核心。与其依赖庞大的继承树, Unity 鼓励 组合多个小型独立组件—— Composition over Inheritance(组合优于继承)。

每个 Component 都继承自 UnityEngine.Component,因此都能访问 gameObject(宿主对象)和 transform

获取引用:GetComponent<T>()。搜索子物体: GetComponentInChildren<T>()。搜索父物体: GetComponentInParent<T>()

关键技能:知道 何时把大脚本拆成多个小 Component。 不要写 500 行的 PlayerController → 拆成 PlayerMovementPlayerCombatPlayerHealth

组合 vs 继承

❌ Inheritance(复杂)

Entity
└─ Character
├─ Player
├─ PlayerWithGun
└─ PlayerWithSword
└─ Enemy
├─ EnemyRanged
└─ EnemyMelee

✅ Composition (Unity)

Movement+Health+GunShoot→ Player+Gun
Movement+Health+AIBrain→ Enemy
Movement+SwordSlash→ Player+Sword

动手步骤

1

从 Inspector 挂载 Component

选中 GO → Add Component → 按名称搜索(Rigidbody、Audio Source…)。

2

在 Awake() 中用 GetComponent 缓存

_rb = GetComponent<Rigidbody>(); 存入私有字段。

3

启用 / 禁用 Component

component.enabled = false/true —— 不会移除组件,只是暂时关闭。

4

用 Interface 松耦合通信

避免脚本之间硬依赖——使用 IDamageableIInteractable

交互模拟器

开关各个 Component,观察角色行为如何变化。留意当前组合的说明。

为 GameObject "Player" 开关组件

😐
👤
No components
Player(GameObject)

当前行为

// GetComponent calls needed:

代码示例

基础
using UnityEngine;

public class ComponentBasics : MonoBehaviour
{
  // Cache: fetch the component once, not every frame
  private Rigidbody _rb;
  private Collider  _col;
  private Renderer  _renderer;

  void Awake()
  {
      _rb       = GetComponent<Rigidbody>();
      _col      = GetComponent<Collider>();
      _renderer = GetComponent<Renderer>();
  }

  void Start()
  {
      // Null-check before use (safe)
      if (_rb != null) _rb.mass = 2f;

      _renderer.enabled = false; // hide the object
      _col.enabled      = false; // disable collisions
  }

  public void MakeInvincible()
  {
      // Disable the AI script (do not remove the component)
      EnemyAI ai = GetComponent<EnemyAI>();
      if (ai != null) ai.enabled = false;
  }
}

代码示例

进阶
using UnityEngine;

// Interface: a contract for any component that can take damage
public interface IDamageable
{
  void TakeDamage(int amount);
}

// Health component: only manages HP, knows nothing about combat
public class Health : MonoBehaviour, IDamageable
{
  [SerializeField] private int maxHP = 100;
  private int _currentHP;

  void Awake() => _currentHP = maxHP;

  public void TakeDamage(int amount)
  {
      _currentHP -= amount;
      if (_currentHP <= 0) Destroy(gameObject);
  }
}

// Bullet component: deals damage without knowing Health exists
public class Bullet : MonoBehaviour
{
  [SerializeField] private int damage = 25;

  void OnCollisionEnter(Collision col)
  {
      // Ask: does this object implement IDamageable? → loose coupling
      col.gameObject.GetComponent<IDamageable>()?.TakeDamage(damage);
      Destroy(gameObject);
  }
}

📌 快速记忆

  • Component = 挂在 GameObject 上的独立模块
  • 优先用组合(多个小组件),而不是深继承链
  • 务必在 Awake() 中缓存到私有字段
  • 用 Interface 让组件通信,互不直接依赖

⚠️ 常见错误

  • ❌ 一个脚本包揽太多职责

    500 行脚本同时管移动、HP、枪械和 UI

    ✅ 拆成 PlayerMovement、PlayerHealth、PlayerWeapon

  • ❌ 在 Update() 里调用 GetComponent<>()

    组件未挂载时会 NullReferenceException

    ✅ 在 Awake() 中缓存,使用前做 null 检查