Đă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.
Thử thách
DễĐể mỗi dân làng chỉ lắng nghe tiếng chuông khi đang hoạt động.
- Trong
Villager.cs, chuyểnbell.OnRing += Hop;từStart()vàovoid OnEnable()mới, rồi xóaStart(). - Thêm
void OnDisable()vớibell.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
1Thành phần, không phải hệ thống phân cấp
Thành phần nhỏTập lệnh kẻ địch cơ sởThành phần trừu tượngCác thành phần phối hợp với nhauÔn tập: tháp pháo mô-đunÔn tập: pháo nòng đôi4Dữ liệu tuần tự hóa
Lớp có thể tuần tự hóaDanh sách trong InspectorKiểu liệt kê trong InspectorÔn tập: Bảng vật phẩm rơiÔn tập: Quay vật phẩm2Giao diện trong Unity
IDamageableGiao diện và TryGetComponentGetComponentsÔn tập: phím tương tácÔn tập: đối tượng gần nhất trong tầm với5ScriptableObjects
Tài sản dữ liệuChỉ số vũ khíCài đặt dùng chungLưu gióSóng dưới dạng dữ liệuÔn tập: Cơ sở dữ liệu vật phẩmÔn tập: Mua hàng từ cửa hàng8Code có thể tái sử dụng
Phương thức mở rộngSingleton tổng quátCác hàm hỗ trợ tổng quátÔn tập: FindNearest3Sự kiện
Sự kiện C# trong UnityĐăng ký trong OnEnableCác trường UnityEventSự kiện điều khiển UIÔn tập: Cửa sổ bật lên thành tíchÔn tập: Bộ hẹn giờ cửa sổ bật lên6Lưu dữ liệu bằng JSON
JsonUtilityLưu trò chơiTải dữ liệu và giá trị mặc địnhÔn tập: các ô lưuChọn và xóa một ô lưu9Tái sử dụng đối tượng bằng pool
Vì sao cần pool đối tượngPool dùng hàng đợiObjectPool của UnityÔn tập: pool đạnTự luyện tập: Playground Unity