Hero image

Sử dụng ScriptableObjects làm kênh sự kiện trong mã trò chơi.

Trang web này đã được dịch bằng máy để thuận tiện cho bạn. Chúng tôi không thể đảm bảo tính chính xác hoặc độ tin cậy của nội dung được dịch. Nếu bạn có thắc mắc về tính chính xác của nội dung được dịch, vui lòng tham khảo phiên bản tiếng Anh chính thức của trang web.

Làm thế nào để bạn kết nối các hệ thống khác nhau trong ứng dụng của mình hoạt động cùng nhau? Một giải pháp phổ biến là sử dụng sự kiện để gửi thông điệp giữa các đối tượng. Hãy tiếp tục đọc để tìm hiểu cách sử dụng ScriptableObjects làm kênh sự kiện trong dự án Unity của bạn.

Đây là bài viết thứ năm trong chuỗi sáu bài hướng dẫn ngắn được tạo ra để hỗ trợ các nhà phát triển Unity với bản demo đi kèm sách điện tử " Tạo kiến ​​trúc trò chơi mô-đun trong Unity với ScriptableObjects" .

Bản demo này lấy cảm hứng từ cơ chế trò chơi điện tử arcade kinh điển với bóng và vợt, và cho thấy cách ScriptableObjects có thể giúp bạn tạo các thành phần có thể kiểm thử, có khả năng mở rộng và thân thiện với nhà thiết kế.

Cả sách điện tử, dự án minh họa và các hướng dẫn ngắn này cùng nhau cung cấp những phương pháp tốt nhất để sử dụng các mẫu thiết kế lập trình với lớp ScriptableObject trong dự án Unity của bạn. Những mẹo này có thể giúp bạn đơn giản hóa mã, giảm mức sử dụng bộ nhớ và thúc đẩy khả năng tái sử dụng mã.

Loạt bài này bao gồm các bài viết sau:

Lưu ý quan trọng trước khi bắt đầu

Trước khi bạn bắt đầu tìm hiểu dự án demo ScriptableObject và loạt bài hướng dẫn ngắn này, hãy nhớ rằng, về bản chất, các mẫu thiết kế chỉ là những ý tưởng. Những điều này không áp dụng cho mọi tình huống. Những kỹ thuật này có thể giúp bạn học được những cách làm việc mới với Unity và ScriptableObjects.

Mỗi kiểu mẫu đều có ưu điểm và nhược điểm riêng. Chỉ chọn những giải pháp mang lại lợi ích thiết thực cho dự án cụ thể của bạn. Các nhà thiết kế của bạn có phụ thuộc nhiều vào Unity Editor không? Một mô hình dựa trên ScriptableObject có thể là lựa chọn tốt để giúp họ cộng tác với các nhà phát triển của bạn.

Tóm lại, kiến ​​trúc mã nguồn tốt nhất là kiến ​​trúc phù hợp với dự án và nhóm của bạn.

Liên kết lỏng lẻo, độ kết dính cao

Khi xây dựng các mô-đun hoặc hệ thống khác nhau trong một ứng dụng, việc coi chúng như những "đảo mã" thường rất hữu ích. Mỗi mô-đun có thể có nhiều thành phần hoặc GameObjects hoạt động cùng nhau để phục vụ một mục đích chung.

Ví dụ, cần điều khiển của người chơi có thể bao gồm một đoạn mã lập trình để diễn giải đầu vào của người chơi, một đoạn mã khác để xử lý chuyển động hoặc va chạm, v.v. Nếu các thành phần này có mối liên hệ phụ thuộc lẫn nhau, bạn có thể sử dụng Trình kiểm tra để tạo ra các kết nối chặt chẽ đó.

Tuy nhiên, hãy nhớ rằng mỗi khi bạn thêm một sự phụ thuộc vào một đối tượng khác, điều đó đều tiềm ẩn một rủi ro nhỏ. Khi có thể, bạn nên giảm thiểu sự phụ thuộc vào các đối tượng bên ngoài. Việc giao tiếp với những thứ nằm ngoài mô-đun hoặc hệ thống của bạn sẽ không được trực tiếp cho lắm.

Bạn có thể cho đoạn mã điều khiển vợt tham chiếu đến quả bóng trong trò chơi của mình, nhưng điều đó có nghĩa là chúng có một mối liên hệ với nhau. Khi chúng có mối quan hệ phụ thuộc, việc thay đổi một thành phần có thể ảnh hưởng đến thành phần còn lại.

Lý tưởng nhất là bạn muốn có thể sửa đổi một phần của ứng dụng mà không làm hỏng bất cứ thứ gì khác. Mục tiêu là giữ cho các mô-đun của bạn có tính liên kết nội bộ nhưng tách biệt với nhau về mặt bên ngoài.

Bạn có thể sử dụng lớp NullRefChecker của dự án để đưa ra cảnh báo lịch sự khi các tham chiếu cần thiết bị thiếu trong Inspector. Đơn giản chỉ cần gọi phương thức Validate tĩnh ở đâu đó (ví dụ: trong Awake ) sau khi mỗi thành phần đã được thiết lập hoặc khởi tạo.

Thêm thuộc tính Tùy chọn tùy chỉnh để bỏ qua việc kiểm tra xem trường đó có thể để trống hay không.

Sử dụng các sự kiện

Vậy làm thế nào để các hệ thống khác nhau trong ứng dụng của bạn hoạt động cùng nhau?

Một giải pháp là sử dụng sự kiện để gửi thông điệp giữa các đối tượng. Các sự kiện tuân theo mô hình người phát - người nghe, được minh họa trong hình ảnh phía trên.

Ở đây, đối tượng lắng nghe đăng ký nhận sự kiện trên bộ phát, thay vì gọi một phương thức hoặc tham chiếu trực tiếp đến một thuộc tính.

Những thay đổi đối với một thành phần sẽ có tác động ít hơn đến các thành phần khác. Mọi thứ vẫn có thể bị lỗi khi bạn sửa đổi mã, nhưng các đối tượng sẽ không còn liên kết chặt chẽ với nhau như trước nữa. Sự kiện ở giữa đóng vai trò như một vùng đệm giữa chúng.

Chúng ta thường mô tả các đối tượng trong mối quan hệ giữa người phát và người nghe này là các đối tượng liên kết lỏng lẻo.
Bạn có thể tìm hiểu thêm về các sự kiện và mẫu thiết kế quan sát trong sách điện tử kỹ thuật của chúng tôi, "Nâng tầm mã nguồn của bạn với các mẫu lập trình trò chơi" .

sự kiện nhà xuất bản

HỆ THỐNG SỰ KIỆN TẬP TRUNG

Các sự kiện tập trung

Trong trường hợp trên, đài phát thanh chỉ chịu trách nhiệm gửi tín hiệu. Nó không quan tâm đối tượng nào đang lắng nghe.

Tuy nhiên, người nghe vẫn cần có một số hiểu biết về người phát sóng để có thể đăng ký và hủy đăng ký nhận thông tin từ người ủy quyền bằng cách sử dụng các phương thức OnEnable và OnDisable.

Bạn có thể tách biệt hơn nữa bộ phát và bộ thu bằng cách chuyển các sự kiện vào một lớp tĩnh. Một lớp "sự kiện trò chơi" tổng quát có thể giúp tạo thêm một lớp trừu tượng giữa hai lớp này. Điều này có thể kết nối người phát sóng và người nghe mà không cần họ biết trực tiếp về nhau.

Trong ví dụ này, để đơn giản, chúng ta sẽ sử dụng lớp GameEvents tĩnh. Tuy nhiên, trong một kịch bản sản xuất thực tế, tốt hơn hết là nên chia nó thành các lớp nhỏ hơn, chuyên biệt theo chức năng, chẳng hạn như UIEvents, GameStateEvents, HealthEvents, InventoryEvents, v.v.

Ví dụ, bạn có thể tạo các sự kiện tĩnh để thoát ứng dụng, hiển thị màn hình giao diện người dùng hoặc tải một cảnh. Bằng cách thiết lập các sự kiện này ở trạng thái tĩnh, chúng có thể được truy cập từ bất kỳ phần nào trong ứng dụng của bạn.

Ví dụ, bạn có thể tạo GameEvents như trong ví dụ bên dưới.

Đối tượng GameEvent tĩnh đóng vai trò trung gian giữa người phát sóng và người nghe ban đầu. Việc thay đổi bên nhận hoặc bên gửi đều có khả năng ảnh hưởng đến bên còn lại thấp hơn.

Do đó, việc cập nhật mã nguồn sẽ ít gây ra các tác dụng phụ không mong muốn hơn. Việc lưu trữ các định nghĩa sự kiện của bạn ở một vị trí duy nhất cũng giúp việc quản lý chúng dễ dàng hơn.

Mặc dù các GameEvent tĩnh rất hiệu quả, nhưng chúng có thể không dễ tiếp cận đối với các nhà thiết kế trò chơi của bạn. Vì chúng là các biến tĩnh, nên chúng phải được định nghĩa trong mã và không thể được tuần tự hóa trực tiếp trong Trình soạn thảo.

Để có một hệ thống thân thiện hơn với người biên tập, hãy cân nhắc triển khai các sự kiện dựa trên ScriptableObjects.

Sử dụng UnityEngine;
sử dụng System;

public static class GameEvents
{
    public static Action ExitApplication;
    public static Action HomeScreenShown;
    Hành động tĩnh công khai LoadProgressUpdated;
}
sự kiện

CÁC KÊNH SỰ KIỆN CHUYỂN TIẾP TÍN HIỆU GIỮA ĐÀI PHÁT THANH VÀ NGƯỜI NGHE.

Cấu hình kênh sự kiện

Các sự kiện dựa trên ScriptableObject cung cấp một giải pháp thay thế trực quan cho các sự kiện tĩnh. Mặc dù cả hai đều có chức năng tương tự, nhưng ScriptableObjects thường thân thiện hơn với người thiết kế vì chúng xuất hiện trong Inspector.

Vì chúng truyền tín hiệu từ đài phát đến người nghe, bạn có thể coi chúng như "kênh sự kiện", tương tự như đường truyền từ tháp phát thanh.

Bất kỳ ScriptableObject nào có các thuộc tính sau đều có thể hoạt động như một kênh sự kiện:

  • Một đối tượng ủy quyền (như UnityAction hoặc System.Action): Điều này thông báo cho người đăng ký và truyền dữ liệu dưới dạng tham số.
  • Một phương pháp gây quỹ sự kiện: Phương thức công khai này gọi đến ủy quyền.

Bạn có thể thiết lập bất kỳ số lượng kênh sự kiện nào để xác định các khía cạnh khác nhau của trò chơi.

UnityAction và System.Action đều là các delegate. Bạn có thể sử dụng một hoặc cả hai loại trong dự án của mình.

UnityAction tạo ra trải nghiệm thân thiện hơn với người dùng nghệ thuật. Nếu không, hãy sử dụng ủy quyền System.Action.

Dưới đây là một ví dụ về VoidEventChannelSO từ dự án. Đây là một sự kiện dựa trên ScriptableObject và không truyền bất kỳ tham số nào.

Ở đây, chúng ta sử dụng một UnityAction có tên là OnEventRaised và công khai phương thức RaiseEvent .

Sử dụng UnityEngine;
Sử dụng UnityEngine.Events;

[CreateAssetMenu(menuName = "Events/Void Event Channel", 
fileName = "VoidEventChannel")]
public class VoidEventChannelSO : Mô tảSO
{
    [Chú thích ("Hành động cần thực hiện")]
    public UnityAction OnEventRaised;

    public void RaiseEvent()
    {
        if (OnEventRaised != null)
            OnEventRaised.Invoke();
    }
}
tab8

TẠO CÁC KÊNH SỰ KIỆN TRONG DỰ ÁN.

Tạo tài sản kênh sự kiện

Tạo tài nguyên kênh sự kiện trong dự án để sử dụng nó. Bạn có thể sử dụng menu Tạo hoặc sao chép một tài nguyên hiện có.

Đổi tên từng tài nguyên và sử dụng trường mô tả để xác định từng tài nguyên ScriptableObject. Hãy nhớ rằng mỗi kênh sự kiện tồn tại như một tài nguyên cấp dự án. Bạn sẽ tham chiếu đến các tài nguyên này trong MonoBehaviours của mình.

Mặc dù không bắt buộc, bạn có thể gắn thẻ các kênh sự kiện dựa trên ScriptableObject bằng hậu tố _SO để phân biệt chúng với các ScriptableObject khác mang dữ liệu (có hậu tố _Data).

Việc sử dụng thư mục và quy ước đặt tên có thể giúp dự án của bạn được sắp xếp gọn gàng. Bạn nên tùy chỉnh chúng cho phù hợp với nhu cầu của dự án. Hãy đọc hướng dẫn "Tạo cẩm nang phong cách C#" để biết thêm thông tin.

tab9

GÁN KÊNH SỰ KIỆN TRONG TRÌNH KIỂM TRA.

Sự kiện gây quỹ

Bất kỳ đối tượng nào trong khung cảnh của bạn giờ đây đều có thể tham chiếu đến kênh sự kiện và gọi sự kiện bằng phương thức RaiseEvent . Ví dụ, hãy xem MonoBehaviour mẫu với phương thức TriggerEvent bên dưới.

Trong cửa sổ Inspector, cần gán tài nguyên ScriptableObject cho trường m_EventChannel . Khi một sự kiện nào đó kích hoạt TriggerEvent , sự kiện đó sẽ được thực thi. Bất cứ thiết bị nào đang lắng nghe sẽ nhận được thông báo.

Cơ chế này giúp tăng thêm tính tương tác cho ứng dụng trò chơi của bạn. Mỗi mô-đun hoặc hệ thống đều tạo ra một sự kiện (ví dụ: hệ thống nhập liệu ghi nhận thao tác nhấn phím, quả bóng va chạm với tường, v.v.). Đáp lại, một điều khác sẽ phản ứng lại.

public class EventRaiser: MonoBehaviour
{
    [SerializeField]
    private VoidEventChannelSO m_EventChannel;

    public void TriggerEvent()
    {
        m_EventChannel.RaiseEvent();
    }
}
tab

NGƯỜI QUẢN LÝ TRÒ CHƠI LẮNG NGHE MỘT SỐ KÊNH SỰ KIỆN NHẤT ĐỊNH VÀ PHÁT SÓNG TRÊN CÁC KÊNH KHÁC.

Lắng nghe các sự kiện

Để thiết lập trình lắng nghe, MonoBehaviour hoặc thành phần khác cần đăng ký sự kiện OnEventRaised của kênh sự kiện. Thông thường điều này xảy ra trong phương thức OnEnable , như trong ví dụ bên dưới.

Khi kênh sự kiện phát sinh một sự kiện, phương thức HandleEvent sẽ được thực thi để phản hồi. Cơ chế này có thể được sử dụng cho nhiều mục đích khác nhau, chẳng hạn như phát âm thanh hoặc hiệu ứng, sửa đổi cài đặt, v.v., tùy thuộc vào ngữ cảnh của sự kiện.

Trong dự án PaddleBallSO , đây là cách chúng tôi thiết lập vòng lặp chính của trò chơi. GameManager lắng nghe một tập hợp các kênh sự kiện, sau đó phát tín hiệu trên một tập hợp khác. Điều này cho phép các hệ thống khác nhau gửi tin nhắn cho nhau mà không nhất thiết phải có sự phụ thuộc trực tiếp.

Cuối cùng, hãy hủy đăng ký sự kiện OnEventRaised trong phương thức OnDisable để tránh lỗi hoặc rò rỉ bộ nhớ.

public class EventListener: MonoBehaviour
{
    [SerializeField]
    private VoidEventChannelSO m_EventChannel;

    private void OnEnable()
    {
        m_EventChannel.OnEventRaised += HandleEvent;
    }

    private void OnDisable()
    {
        m_EventChannel.OnEventRaised -= HandleEvent;
    }

    private void HandleEvent()
    {
        Debug.Log("Sự kiện đã được nhận");
    }
}
tab10

THIẾT LẬP TƯƠNG TÁC KHÔNG CẦN MÃ TRONG TRÌNH KIỂM TRA

Thêm trình lắng nghe không cần mã

Nếu bạn đang làm việc với các nhà thiết kế, bạn có thể muốn cung cấp cho họ một kịch bản đa năng được cấu hình sẵn có khả năng lắng nghe một sự kiện. Điều này sẽ cho phép họ tạo các tương tác trong game mà không cần lập trình viên.

Lớp VoidEventChannelListener là một ví dụ điển hình. Thành phần này sẽ tạo ra một UnityEvent khi nhận được tín hiệu từ một kênh sự kiện. Đơn giản chỉ cần thêm VoidEventChannelListener vào một GameObject, sau đó thiết lập kênh sự kiện và logic UnityEvent.

Nhờ đó, nhà thiết kế có thể tạo nguyên mẫu cho logic hướng sự kiện chỉ với một vài thiết lập trong Inspector.

Ví dụ, prefab GameOverSounds lắng nghe kênh sự kiện GameOver_SO . Khi nhận được sự kiện này, nó sẽ phát lại âm thanh trên AudioSource được chỉ định thông qua UnityEvent m_Response .

Lớp VoidEventChannelListener cũng bao gồm một độ trễ hữu ích để điều chỉnh thời gian cho mỗi phản hồi.

Với một chút luyện tập, đây là một cách đơn giản để xây dựng sự tương tác giữa các hệ thống và mô-đun khác nhau của bạn.

tab11

KÊNH SỰ KIỆN ĐƯỢC ĐÁNH DẤU ĐỂ GỬI VÀ NHẬN

Các kênh sự kiện giúp ích như thế nào?

Vì tồn tại ở cấp độ dự án, các kênh sự kiện có thể truy cập được trên toàn cầu. Điều này cho phép họ kết nối bất kỳ đối tượng nào trong Cấu trúc phân cấp cảnh và duy trì kết nối đó qua các lần tải cảnh.

Bất kỳ đối tượng nào cũng có thể hoạt động như một thiết bị phát hoặc thiết bị thu – vấn đề chỉ là cách nó tương tác với kênh sự kiện. Điều này mang lại cho bạn rất nhiều sự linh hoạt trong việc gửi tin nhắn.

Ghi chú : Nên ghi rõ trong phần Kiểm tra xem kênh đó dùng để gửi hay nhận dữ liệu. Hãy sử dụng thuộc tính HeaderAttribute để thực hiện điều này.

Một lợi ích khác của việc sử dụng các sự kiện ở cấp độ dự án là chúng thường có thể thay thế nhu cầu sử dụng đối tượng duy nhất (singleton). Các kênh sự kiện có sẵn trên toàn cầu, vì vậy chúng có thể kết nối mọi thứ với mọi thứ. Hãy để họ điều khiển các hệ thống trong game như camera, nhiệm vụ, sức khỏe và thành tích – tất cả mà không tạo ra sự phụ thuộc không cần thiết.

Ngoài ra, vì kiến ​​trúc dựa trên sự kiện chỉ thực thi khi cần thiết, nên nó được tối ưu hóa hơn so với các phương thức cập nhật của MonoBehaviour.

Chữ ký hàm của một sự kiện cơ bản

Lớp VoidEventChannelSO này chỉ hoạt động với các sự kiện không cần tham số. Thông thường, sự kiện được tạo ra cần thêm dữ liệu bổ sung để có ý nghĩa.

Ví dụ, nếu bạn đang gửi một sự kiện gây sát thương vào hệ thống sức khỏe, bạn có thể muốn truyền giá trị cho mục tiêu, lượng sát thương cần gây ra, loại sát thương, v.v.

Bạn có thể thay đổi chữ ký hàm của sự kiện cơ bản để làm cho kênh sự kiện phù hợp hơn. Dự án định nghĩa một GenericEventChannelSO cho mục đích đó. Hãy xem ví dụ bên dưới.

Đây là một lớp trừu tượng với một tham số chung duy nhất. Bạn sẽ tạo ra các kênh sự kiện khác từ đó. Sau đó, chúng có thể truyền một tham số duy nhất, chẳng hạn như float, số nguyên hoặc boolean.

Giống như VoidEventChannelSO, GenericEventChannelSO cũng có một UnityAction tên là OnEventRaised. Tuy nhiên, lần này hành động mang một tham số thuộc loại T.

Các đối tượng bên ngoài sẽ gọi phương thức RaiseEvent công khai tương ứng. Nếu sự kiện có các trình lắng nghe, thì nó sẽ được thực thi đồng thời truyền một tham số nhất định.

public abstract class GenericEventChannelSO : Mô tảSO
{
    public UnityAction Khi Sự kiện được kích hoạt;

    public void RaiseEvent(T parameter)
    {
        if (OnEventRaised == null)
            trở lại;

        OnEventRaised.Invoke(parameter);
    }
}

Tạo các kênh sự kiện cụ thể

Giờ bạn chỉ cần tạo các kênh sự kiện cụ thể từ GenericEventChannelSO và điền giá trị cho T.

Ngoài thuộc tính CreateAssetMenu thông thường, không cần thêm bất kỳ chi tiết triển khai cụ thể nào khác.

Việc tạo một kênh sự kiện mang giá float, FloatEventChannelSO , rất đơn giản. Hãy xem ví dụ mã lệnh bên dưới.

Đơn giản vậy thôi! Hãy sử dụng quy trình này để tạo thêm các quy trình tương tự cho BoolEventChannelSO, IntEventChannelSO, v.v.

Nếu bạn cần nhiều hơn một tham số làm dữ liệu truyền tải, hãy định nghĩa thêm các lớp chung (ví dụ: GenericEventChannelSO, GenericEventChannelSO, v.v.) khi cần thiết.

[CreateAssetMenu(menuName = "Events/Float EventChannel", fileName = "FloatEventChannel")]
public class FloatEventChannelSO : GenericEventChannelSO {}
tab11

TRÌNH TỰ CÁC SỰ KIỆN KHI BÓNG CHẠM VÀO BÀN THẮNG

Tổng hợp lại tất cả

Ý tưởng là chia ứng dụng thành các phần nhỏ hơn, có tính mô-đun cao hơn. Việc thiết lập ranh giới rõ ràng giữa chúng giúp ngăn chặn các phần đó đan xen vào nhau do sự phụ thuộc và giúp tránh tình trạng mã nguồn rối rắm.

Các thành phần không có thông tin trực tiếp về các đối tượng bên ngoài không thể thao tác với những thứ mà chúng không được phép thao tác. Thay vào đó, họ buộc phải gửi và nhận tin nhắn thông qua các kênh sự kiện.

Bạn có thể thấy cách thức hoạt động này nếu bạn theo dõi một chuỗi ngắn các pha chơi bóng bàn. Ví dụ, hãy tưởng tượng điều gì xảy ra khi một Quả bóng va chạm với một Bàn thắng:

Thành phần ScoreGoal ghi nhận một va chạm. Sau khi phát hiện quả bóng, nó sẽ tạo ra một sự kiện trên kênh sự kiện GoalHit_SO . Thao tác này truyền ID người chơi của cầu thủ ghi bàn.

Kênh sự kiện này thông báo cho GameManager , và GameManager sẽ đáp lại bằng cách tạo ra một kênh sự kiện khác có tên là PointsScored_SO . Điều này cũng truyền ID người chơi.

Kênh này thông báo cho ScoreManager , từ đó tăng điểm số (được lưu trữ trong một đối tượng riêng biệt) và cập nhật các thành phần giao diện người dùng. Sau đó, nó truyền điểm số của cả hai người chơi thông qua kênh sự kiện ScoreManagerUpdated_SO .

Để đáp lại, mục tiêu ScoreObjective_SO kiểm tra xem một người chơi đã đạt được điểm số mục tiêu hay chưa.

Nếu điều kiện thắng cuộc được đáp ứng, trò chơi kết thúc. Ngược lại, GameManager sẽ thiết lập lại vòng đấu và quả bóng sẽ được đưa trở lại cuộc chơi.

Thoạt nhìn, việc tăng điểm số lên một điểm có vẻ như là một công việc thừa thãi. Tuy nhiên, mục đích là để tách riêng tất cả các thành phần liên quan: Quả bóng, Trình quản lý điểm số, Trình quản lý trò chơi, Trình quản lý mục tiêu, v.v.

Mỗi phần của ứng dụng đều có một mức độ tự chủ nhất định, và điều đó giúp việc kiểm thử từng phần trở nên dễ dàng hơn. Việc bổ sung các hệ thống mới không nhất thiết phải làm gián đoạn logic hiện có. Trên thực tế, lối chơi gốc hoàn toàn không hề để ý đến chúng.

Hãy tưởng tượng bạn muốn thêm các hiệu ứng phụ như âm thanh và hoạt hình để hỗ trợ quá trình chấm điểm. Bạn có thể tạo các thành phần mới lắng nghe các sự kiện phù hợp và phản hồi một cách thích hợp. Logic cơ bản và lối chơi cốt lõi có thể vẫn được giữ nguyên ngay cả khi bạn thêm các hệ thống mới.

Hãy nhớ rằng phương châm trong lập trình SOLID là “mở rộng được, nhưng không cho phép sửa đổi”. Bạn muốn có khả năng thêm chức năng mới vào phần mềm mà không cần phải thay đổi mã nguồn hiện có. Việc sử dụng các kênh sự kiện như thế này giúp tăng khả năng mở rộng.

thanh tra

VIẾT KỊCH BẢN TRÌNH BIÊN TẬP CÓ THỂ GIÚP GỠ LỖI CÁC SỰ KIỆN.

Gỡ lỗi sự kiện

Kiến trúc hướng sự kiện giúp đơn giản hóa việc gỡ lỗi và bảo trì. Các thành phần nhỏ hơn sẽ dễ kiểm thử hơn, cho dù bạn đang viết các bài kiểm thử đơn vị tự động bằng Unity Test Framework hay chỉ đơn giản là khắc phục sự cố một cách không chính thức. Điều này cho phép bạn tập trung vào một vấn đề cụ thể và tiến hành thử nghiệm riêng biệt.

Việc lập trình tùy chỉnh có thể hỗ trợ ở đây. PaddleBallSO giới thiệu một vài công cụ giúp theo dõi luồng hoạt động của ứng dụng khi sử dụng kênh sự kiện:

  • Hầu hết các kênh sự kiện trong dự án PaddleBallSO đều hiển thị danh sách người nghe trong Inspector. Nhấp vào tên của từng người nghe để làm nổi bật họ trong hệ thống phân cấp.
  • Nút RaiseEvent tùy chỉnh có thể kích hoạt một sự kiện giả lập theo ý muốn (sử dụng giá trị mặc định là T nếu mang theo dữ liệu). Trong khi ứng dụng đang chạy, bạn chỉ cần kích hoạt nó thủ công bằng một cú nhấp chuột.

Khi khắc phục sự cố kênh sự kiện, hãy chọn tài nguyên ScriptableObject. Kiểm tra sự kiện thủ công khi cần thiết. Thanh tra có thể hướng dẫn bạn tìm ra những vật thể có thể đang nghe lén. Chọn những người nghe mà bạn muốn kiểm tra chi tiết hơn.

Nếu bạn đã gắn nhãn cho các kênh sự kiện bằng HeaderAttritute, bạn có thể truy ngược lại một số sự kiện để hiểu được luồng logic.

phần kết có thể lập trình

Thêm tài nguyên ScriptableObject

Chúng tôi hy vọng rằng các kênh sự kiện và kiến ​​trúc hướng sự kiện có thể mang lại lợi ích cho các dự án mới và sắp tới của bạn.

Tìm hiểu thêm về các mẫu thiết kế với ScriptableObjects trong sách điện tử kỹ thuật của chúng tôi, "Tạo kiến ​​trúc trò chơi mô-đun trong Unity với ScriptableObjects" . Bạn cũng có thể tìm hiểu thêm về các mẫu thiết kế phát triển Unity phổ biến trong bài viết "Nâng tầm mã nguồn của bạn với các mẫu lập trình game" .