Menu
CoddyTech

Đăng ký trong OnEnable

Thuộc phần Kiến trúc trò chơi trong Unity trong hành trình Unity của Coddy. Bài học 13 trên 64.

Một listener bị hủy sẽ không tự rời khỏi sự kiện. Sự kiện vẫn giữ phương thức của nó, và lần gọi Invoke tiếp theo sẽ gọi phương thức đó trên component đã bị hủy. Lần đầu dùng transform trong phương thức đó sẽ gây ra MissingReferenceException, và vì ngoại lệ kết thúc Invoke nên các listener phía sau cũng bị bỏ qua. Vì vậy, mỗi += đều cần có -=, và cặp phương thức Unity dùng cho việc này là OnEnable và OnDisable:

public class Guard : MonoBehaviour
{
    public Alarm alarm;

    void OnEnable()
    {
        alarm.OnTriggered += RunTo;
    }

    void OnDisable()
    {
        alarm.OnTriggered -= RunTo;
    }

    void RunTo(Vector3 spot)
    {
        transform.LookAt(spot);
    }
}

Unity gọi OnDisable khi đối tượng bị tắt bằng SetActive(false), khi script bị tắt và khi đối tượng bị hủy, trước OnDestroy. OnEnable chạy mỗi lần đối tượng được bật lại. Với cặp phương thức này, một guard chỉ lắng nghe khi đang hoạt động: guard bị hủy sẽ không còn trong sự kiện, guard bị tắt trong một cảnh cắt sẽ bỏ qua báo động, và khi được bật lại, nó sẽ tiếp tục lắng nghe.

Hai cách kết hợp khác sẽ gây ra lỗi. Nếu dùng += trong Start và -= trong OnDisable, guard bị tắt rồi bật lại sẽ không lắng nghe nữa, vì Start chỉ chạy một lần. Nếu dùng += trong OnEnable mà không có -=, mỗi lần bật lại sẽ thêm RunTo một lần nữa, và một báo động sẽ gọi phương thức này hai lần. Xóa một phương thức chưa được đăng ký sẽ không làm gì cả, vì vậy không cần kiểm tra trước khi dùng -= trong OnDisable.

challenge icon

Thử thách

Dễ

Để mỗi dân làng chỉ lắng nghe tiếng chuông khi đang hoạt động.

  1. Trong Villager.cs, chuyển bell.OnRing += Hop; từ Start() vào void OnEnable() mới, rồi xóa Start().
  2. Thêm void OnDisable() với bell.OnRing -= Hop;. Nút "Kiểm tra" sẽ tắt rồi bật Cleo để kiểm tra.

Nhấn Chơi và rung chuông bốn lần: Ana về nhà sau tiếng chuông thứ 2 và không có lỗi nào xuất hiện. Sau đó nhấn Kiểm tra.

Tự làm thử

using UnityEngine;

public class Villager : MonoBehaviour
{
    public Bell bell;
    public int ringsToLeave = 3;
    public int hops;

    void Start()
    {
        bell.OnRing += Hop;
    }

    void Update()
    {
        // rơi trở lại mặt đất sau một lần nhảy
        Vector3 p = transform.position;
        transform.position = new Vector3(p.x, Mathf.MoveTowards(p.y, 0.5f, 4f * Time.deltaTime), p.z);
    }

    void Hop(int ring)
    {
        hops++;
        transform.position += Vector3.up * 0.8f;
        if (hops == ringsToLeave)
        {
            Debug.Log(name + " goes home");
            Destroy(gameObject);
        }
    }
}

Tất cả bài học trong Kiến trúc trò chơi trong Unity

Tự luyện tập: Playground Unity