Unity Term Book
Core & Architecture

Component

Các khối chức năng độc lập gắn vào GameObject — mỗi Component định nghĩa một khía cạnh hành vi, giúp xây dựng game theo nguyên tắc Composition over Inheritance.

Hãy tưởng tượng...

Component giống như module phụ kiện trên xe đua. Thân xe (GameObject) tự nó không làm gì — nhưng khi gắn vào động cơ (Rigidbody), bánh xe (Collider), hệ thống lái (Script) và đèn (Light), xe bắt đầu có hành vi hoàn chỉnh. Quan trọng là mỗi module hoạt động độc lập, tháo đèn ra không ảnh hưởng động cơ.

Khái niệm chi tiết

Component là trái tim của kiến trúc Unity. Thay vì tạo cây kế thừa khổng lồ, Unity khuyến khích kết hợp các component nhỏ độc lậpComposition over Inheritance.

Mọi Component kế thừa từ UnityEngine.Component, nên đều có thể truy cập gameObject (object chứa nó) và transform.

Để lấy tham chiếu: GetComponent<T>(). Tìm ở Children: GetComponentInChildren<T>(). Tìm ở Parent: GetComponentInParent<T>().

Kỹ năng quan trọng: biết khi nào nên tách script lớn thành nhiều Component nhỏ. Thay vì PlayerController 500 dòng → chia thành PlayerMovement, PlayerCombat, PlayerHealth.

Composition vs Inheritance

❌ Inheritance (Phức tạp)

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

✅ Composition (Unity)

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

Hướng dẫn thực hành

1

Gắn Component từ Inspector

Chọn GO → Add Component → tìm tên (Rigidbody, Audio Source...).

2

Cache bằng GetComponent trong Awake()

_rb = GetComponent<Rigidbody>(); lưu vào biến private.

3

Bật/tắt Component

component.enabled = false/true — không xóa, chỉ tạm vô hiệu.

4

Dùng Interface để giao tiếp lỏng lẻo

Tránh phụ thuộc trực tiếp giữa các script — dùng IDamageable, IInteractable...

Trình mô phỏng tương tác

Bật/tắt các Component để xem nhân vật thay đổi hành vi. Quan sát mô tả theo tổ hợp đang bật.

Chọn Components để gắn vào GameObject "Player"

😐
👤
No components
Player(GameObject)

Hành vi hiện tại

// GetComponent calls needed:

Ví dụ Code

Cơ bản
using UnityEngine;

public class ComponentBasics : MonoBehaviour
{
  // Cache: lấy component 1 lần, không lấy mỗi frame
  private Rigidbody _rb;
  private Collider  _col;
  private Renderer  _renderer;

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

  void Start()
  {
      // Kiểm tra null trước khi dùng (an toàn)
      if (_rb != null) _rb.mass = 2f;

      _renderer.enabled = false; // ẩn vật thể
      _col.enabled      = false; // tắt va chạm
  }

  public void MakeInvincible()
  {
      // Tắt script AI (không xóa component)
      EnemyAI ai = GetComponent<EnemyAI>();
      if (ai != null) ai.enabled = false;
  }
}

Ví dụ Code

Nâng cao
using UnityEngine;

// Interface: "hợp đồng" cho mọi component có thể nhận damage
public interface IDamageable
{
  void TakeDamage(int amount);
}

// Component Health: chỉ quản lý máu, không biết về 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);
  }
}

// Component Bullet: gây damage mà không cần biết Health tồn tại
public class Bullet : MonoBehaviour
{
  [SerializeField] private int damage = 25;

  void OnCollisionEnter(Collision col)
  {
      // Hỏi: object này có IDamageable không? → loose coupling
      col.gameObject.GetComponent<IDamageable>()?.TakeDamage(damage);
      Destroy(gameObject);
  }
}

📌 Ghi nhớ nhanh

  • Component = module độc lập gắn vào GameObject
  • Dùng Composition (nhiều component nhỏ) thay vì kế thừa dài
  • Luôn cache bằng biến private trong Awake()
  • Dùng Interface để components giao tiếp không phụ thuộc trực tiếp

⚠️ Lỗi thường gặp

  • ❌ Một script làm quá nhiều việc

    Script 500 dòng, quản lý cả di chuyển, máu, súng, UI

    ✅ Tách thành PlayerMovement, PlayerHealth, PlayerWeapon

  • ❌ GetComponent<>() trong Update()

    NullReferenceException nếu component chưa gắn

    ✅ Cache trong Awake() và kiểm tra null trước khi dùng