Unity Term Book
Scripting & Lifecycle

Awake & Start

Awake chạy ngay khi object được tạo (kể cả khi disabled); Start chạy ở frame đầu tiên khi object enable — sau khi mọi Awake trong scene đã xong. Nhớ thứ tự này.

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

Awake = chuẩn bị cá nhân trước khi đến nơi làm việc — tự mặc đồ, lấy xe, không liên quan đến ai khác. Start = họp buổi sáng đầu ca — tất cả mọi người đã có mặt (Awake đã chạy hết), giờ mới bắt đầu phân công công việc liên kết nhau (GameManager.Instance, tìm đối tượng khác...).

Khái niệm chi tiết

Awake() được gọi đúng một lần khi instance được tạo — kể cả khi component đang bị enabled = false. Đây là nơi lý tưởng để khởi tạo tham chiếu nội bộ: _rb = GetComponent<Rigidbody>().

Start() được gọi frame đầu tiên sau khi component enabled. Vì tất cả Awake() trong scene đã chạy trước, Start an toàn để truy cập Singleton, tìm object khác, hoặc đăng ký event. Nếu component bị disable rồi enable lại, Start không chạy lại.

Thứ tự thực thi: Unity chạy Awake của tất cả script trước, rồi mới chạy Start của tất cả script. Tuy nhiên thứ tự giữa các script không được đảm bảo — trừ khi dùng Script Execution Order trong Project Settings.

Lưu ý khi Instantiate: object tạo runtime cũng chạy Awake + Start theo thứ tự tương tự. Awake chạy ngay khi Instantiate() trả về; Start chạy đầu frame kế tiếp.

Thứ tự thực thi với nhiều Script

⚡ Giai đoạn AWAKE (trước frame đầu)

GameManager.Awake()

_instance = this

PlayerCtrl.Awake()

_rb = GetComponent()

EnemyAI.Awake()

_nav = GetComponent()

🚀 Giai đoạn START (frame đầu tiên)

GameManager.Start()

LoadLevel(1)

PlayerCtrl.Start()

GameManager.Instance ✅

EnemyAI.Start()

FindPlayer() ✅

🔄 Update Loop (mỗi frame)

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

1

Awake: tự khởi tạo nội bộ

Cache GetComponent<T>(), khởi tạo biến private, setup Singleton. Không gọi object khác.

2

Start: kết nối với thế giới bên ngoài

Truy cập GameManager.Instance, FindObjectOfType<T>(), đăng ký event.

3

Dùng Script Execution Order nếu cần

Edit → Project Settings → Script Execution Order → kéo script lên đầu danh sách để đảm bảo chạy trước.

4

Tránh null reference giữa script

Nếu ScriptA.Awake truy cập ScriptB (chưa Awake), sẽ null. Dùng Start để truy cập cross-script.

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

Thêm script vào scene và nhấn Load Scene để xem thứ tự gọi Awake và Start của từng script.

Scripts in Scene

Execution Log

Add scripts rồi Load Scene...

Phase: Idle|Add ít nhất 2 scripts và nhấn Load Scene

Ví dụ Code

Cơ bản

Singleton pattern với Awake, và component dùng Start để kết nối.

public class GameManager : MonoBehaviour
{
  public static GameManager Instance { get; private set; }

  void Awake()
  {
      // Singleton setup — chạy trước mọi Start()
      if (Instance != null) { Destroy(gameObject); return; }
      Instance = this;
      DontDestroyOnLoad(gameObject);
  }
}

public class PlayerController : MonoBehaviour
{
  private Rigidbody _rb;

  void Awake() => _rb = GetComponent<Rigidbody>();

  void Start()
  {
      // An toàn: GameManager.Awake() đã chạy xong
      GameManager.Instance.RegisterPlayer(this);
  }
}

Ví dụ Code

Nâng cao

Kiểm soát thứ tự Awake bằng [DefaultExecutionOrder] attribute.

using UnityEngine;

// Chạy trước tất cả script khác (giá trị âm = ưu tiên cao hơn)
[DefaultExecutionOrder(-100)]
public class ServiceLocator : MonoBehaviour
{
  public static ServiceLocator Instance { get; private set; }
  private Dictionary<System.Type, MonoBehaviour> _services = new();

  void Awake()
  {
      Instance = this;
      // Tự động tìm và đăng ký tất cả IService trong scene
      foreach (var svc in FindObjectsOfType<MonoBehaviour>())
          if (svc is IService)
              _services[svc.GetType()] = svc;
  }

  public T Get<T>() where T : MonoBehaviour =>
      _services.TryGetValue(typeof(T), out var s) ? s as T : null;
}

// Bất kỳ script nào cũng dùng Start để lấy service:
// var gm = ServiceLocator.Instance.Get<GameManager>();

📌 Ghi nhớ nhanh

  • Awake: tự chuẩn bị, không cần ai khác
  • Start: kết nối với scene — chạy sau toàn bộ Awake
  • Start không chạy lại khi enable/disable
  • Dùng [DefaultExecutionOrder] để đảm bảo thứ tự

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

  • ❌ Truy cập Singleton trong Awake()

    Singleton chưa chắc đã Awake — NullReferenceException

    ✅ Truy cập Singleton trong Start()

  • ❌ Khởi tạo Singleton bằng Start()

    Script khác Awake xong mà Singleton chưa có → null

    ✅ Luôn khởi tạo Singleton trong Awake()