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 → 拆成 PlayerMovement、
PlayerCombat、PlayerHealth。
组合 vs 继承
❌ Inheritance(复杂)
✅ Composition (Unity)
动手步骤
从 Inspector 挂载 Component
选中 GO → Add Component → 按名称搜索(Rigidbody、Audio Source…)。
在 Awake() 中用 GetComponent 缓存
_rb = GetComponent<Rigidbody>(); 存入私有字段。
启用 / 禁用 Component
component.enabled = false/true —— 不会移除组件,只是暂时关闭。
用 Interface 松耦合通信
避免脚本之间硬依赖——使用 IDamageable、IInteractable…
交互模拟器
开关各个 Component,观察角色行为如何变化。留意当前组合的说明。
为 GameObject "Player" 开关组件
当前行为
代码示例
基础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 检查