Hero image

Sử dụng kiểu liệt kê dựa trên ScriptableObject trong dự án Unity của bạn.

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.

Trang này giải thích cách sử dụng các kiểu liệt kê dựa trên ScriptableObject trong dự án Unity của bạn.

Đây là bài viết thứ ba 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.

tab 1

VIỆC XÓA HOẶC SẮP XẾP LẠI CÁC GIÁ TRỊ ENUM CÓ THỂ DẪN ĐẾN NHỮNG HÀNH VI KHÔNG MONG MUỐN.

Enum có thể mở rộng

Enum là một cách tiện dụng để quản lý một tập hợp các giá trị được đặt tên cố định trong mã của bạn. Tuy nhiên, chúng cũng có một số hạn chế. Vì các giá trị enum được tuần tự hóa được lưu trữ dưới dạng số nguyên chứ không phải tên ký hiệu của chúng, việc xóa hoặc sắp xếp lại thứ tự một giá trị có thể dẫn đến hành vi không chính xác hoặc không mong muốn. Điều này có nghĩa là các kiểu liệt kê (enum), đặc biệt là khi bạn có rất nhiều kiểu liệt kê, có thể tạo nhiều rắc rối trong quá trình phát triển Unity .

Phương pháp tiêu chuẩn

Đây là hình dạng điển hình của một kiểu liệt kê (enum):

[System.Serializable]
public enum HandGestures
{
Rock,
Giấy,
Kéo
}

Bạn có thể tuần tự hóa một kiểu liệt kê bằng thuộc tính System.Serializable và nó sẽ hiển thị trong Inspector.

Vấn đề

Việc sắp xếp lại hoặc xóa một giá trị có thể gây ra sự cố. Vì mỗi giá trị bên trong đều là một số nguyên, nên những gì nó biểu thị có thể trở thành một thứ khác. Trong ví dụ đã cho, việc xóa giá trị Giấy sẽ khiến Kéo có giá trị là 1.

Hoặc, nếu chúng ta thêm một giá trị như trong ví dụ bên dưới.

Giá trị enum được chọn sẽ thay đổi nếu nó nằm sau mục đã bị xóa.

Điều này có thể gây ra vấn đề khi bảo trì và cập nhật dự án, đặc biệt khi kiểu liệt kê của bạn chứa nhiều giá trị. Bạn có thể giảm thiểu vấn đề này bằng cách để trống hoặc không sử dụng một phần tử nào đó, hoặc bằng cách thiết lập rõ ràng các giá trị số nguyên. Tuy nhiên, cả hai giải pháp đều không lý tưởng.

[System.Serializable]
public enum HandGestures 
{
    Rock,
    Paper,
    ThumbsUp,    // inserted value
    Scissors
}
tab3

KIỂM TRA SỰ BẰNG NHAU GIỮA CÁC ĐỐI TƯỢNG CÓ THỂ LẬP TRÌNH

Enum dựa trên ScriptableObject

Các kiểu liệt kê dựa trên ScriptableObject cung cấp cho bạn chức năng của các kiểu liệt kê truyền thống nhưng được lưu trữ dưới dạng các tài sản riêng lẻ. Ví dụ, hãy xem ScriptableObject PlayerIDSO trong dự án PaddleBallSO ở ví dụ bên dưới.

Về cơ bản, đây là một ScriptableObject trống.

Bạn có thể sử dụng điều đó để tạo một số tài sản ScriptableObject trong dự án, chẳng hạn như P1, P2, v.v. Ngay cả khi chúng không chứa bất kỳ dữ liệu nào, bạn vẫn có thể sử dụng ScriptableObjects để so sánh. Đơn giản chỉ tạo một tài nguyên ScriptableObject mới trong dự án và đặt tên cho nó.

Bạn có thể tạo bao nhiêu ID người chơi tùy thích trong dự án và dễ dàng chuyển đổi giữa chúng. Chỉ cần thay đổi tài nguyên được gán trong tập lệnh GameDataSO.

Nếu bạn đang kiểm tra sự bằng nhau, điều này hoạt động tương tự như kiểu liệt kê (enum). Hai biến có cùng tham chiếu đến một ScriptableObject không? Nếu vậy, chúng là cùng một loại mặt hàng. Ngược lại, chúng không phải vậy.

Ngay cả khi không có dữ liệu bổ sung nào, ScriptableObject vẫn đại diện cho một danh mục hoặc loại mặt hàng.

[CreateAssetMenu(fileName = "PlayerID")]
public class PlayerIDSO: ScriptableObject
{
}

Mã định danh người chơi trong PaddleBallSO

Trong PaddleBallSO , PlayerIDSO trở thành tên gọi của đội. Chúng tôi sử dụng các tài sản P1 và P2 trong GameDataSO để phân biệt giữa hai cần điều khiển.

Tập lệnh GameSetup gán cho mỗi cần gạt một ID người chơi. Trong quá trình chơi game, các đoạn mã của Paddle sẽ so sánh thao tác nhập liệu của người chơi với ID đội được chỉ định.

Điều này có thể áp dụng cho mọi loại trò chơi nhiều người chơi. Ngoài ra, hãy cân nhắc áp dụng chúng ở bất cứ nơi nào khác bạn cần sử dụng kiểu liệt kê.

Vì chúng chỉ đơn thuần là các phép gán trong Inspector, nên ScriptableObjects không gặp phải các vấn đề tương tự về đổi tên và sắp xếp lại thứ tự.

Bạn muốn đổi tên định danh thành “Player1” hoặc “Player2” tương ứng? Bạn có thể làm như vậy, và mọi thứ vẫn tiếp tục hoạt động bình thường. Bạn muốn thêm nhiều ScriptableObject hơn? Không vấn đề gì – việc phân bổ tài nguyên trong Trình kiểm tra vẫn giữ nguyên.

tab5

CÁC KHỐI SỬ DỤNG CÁC NHÓM ĐƯỢC CHỈ ĐỊNH ĐỂ SO SÁNH.

Bản demo các mẫu

Hành vi này hữu ích cho việc tạo ra lối chơi. Trong bản demo Patterns, hãy nhấp vào nút Switch Enum để thay đổi nhóm. Một MonoBehaviour trên DemoBall sẽ cập nhật SpriteRenderer cho phù hợp.

Khi quả bóng va chạm, nó có gây sát thương cho khối xây dựng không? Hãy tìm hiểu bằng cách thực hiện một bài kiểm tra nhanh về sự bình đẳng. Dưới đây là một cách để so sánh chúng trong ví dụ mã lệnh.

Phương pháp này có thể xác định xem hai GameObjects có cùng phe hay không, điều này rất hữu ích khi kiểm tra tương tác giữa đồng minh và kẻ thù. Phép so sánh đơn giản này có thể áp dụng cho việc nhặt vật phẩm, sát thương, hoặc bất cứ thứ gì khác có "đội" hoặc "liên kết".

public static bool AreEqual(GameObject a, GameObject b)
{
    TeamID teamA = a.GetComponent<TeamID>();
    TeamID teamB = b.GetComponent<TeamID>();

    // If both are not null and have matching IDs
    if (teamA != null && teamB != null)
    {
        return teamA.ID == teamB.ID;
    }

    // Otherwise, return false
    return false;
}

Mở rộng hành vi

Phần thú vị nằm ở chỗ bạn thêm logic vào các ScriptableObject của mình. Khác với kiểu liệt kê thông thường, ScriptableObject có thể có các trường và phương thức, ngoài việc lưu trữ dữ liệu.

Hãy sử dụng chúng để mỗi ScriptableObject có thể có logic so sánh chuyên biệt. Ví dụ, bạn có thể có một ScriptableObject định nghĩa các hiệu ứng sát thương đặc biệt (ví dụ: lạnh, nóng, điện, phép thuật, v.v.).

Nếu ứng dụng của bạn yêu cầu một hệ thống kho đồ để trang bị các vật phẩm trong trò chơi, ScriptableObjects có thể đại diện cho các loại vật phẩm hoặc vị trí vũ khí. Liệu một số nhân vật có bị cấm giữ một số vật phẩm nhất định không? Một số vật phẩm có phép thuật hay sở hữu khả năng đặc biệt nào không? Các kiểu liệt kê dựa trên ScriptableObject có thể thêm các phương thức để kiểm tra điều đó.

Đối MonoBehaviour DemoBall trong ví dụ trước bao gồm phương thức AreEqual để so sánh các ScriptableObject. Khi mở rộng hành vi, bạn có thể đóng gói logic so sánh bên trong chính ScriptableObject.

Trong bản demo Patterns, bạn có thể điều chỉnh quả bóng để nó chọn lọc hơn khi va chạm với vật thể. Hãy xem ví dụ về một thành phần đa năng dùng để xử lý va chạm trong đoạn mã bên dưới.

Phương pháp này có thể đạt được kết quả tương tự như bản demo hiện tại, nhưng giờ đây nó có thêm trường m_Weakness . Điều này cho phép mỗi ScriptableObject định nghĩa một ScriptableObject khác để hủy khi xảy ra xung đột.

Thay vì gọi phương thức AreEqual , mỗi ScriptableObject tự quản lý logic so sánh của riêng nó.

Kết quả là sản phẩm linh hoạt và có khả năng mở rộng hơn. Thay vì để quả bóng phá hủy hàng phòng ngự của một đội khác, bạn có thể nhắm mục tiêu cụ thể hơn. Nhiều quả bóng trong khung cảnh có thể phá hủy các khối khác nhau, tùy thuộc vào CollisionItems riêng của chúng.

Điều này tạo tiền đề cho những tương tác khác nhau, phức tạp hơn. Nếu bạn muốn tạo một hệ thống oẳn tù tì, bạn có thể định nghĩa ba ScriptableObject: Oẳn tù tì. Mỗi bên có thể có m_Weakness riêng biệt và sử dụng phương thức IsWinner để xử lý các tương tác.

Không giống như kiểu liệt kê (enums), ScriptableObjects giúp quá trình này trở nên có tính mô-đun và dễ thích ứng. Không cần phải dựa vào các cấu trúc dữ liệu bổ sung hoặc thêm logic phức tạp để đồng bộ hóa với một tập dữ liệu riêng biệt. Chỉ cần thêm một trường và/hoặc phương thức bổ sung để xử lý logic.

public class CollisionItem: ScriptableObject
{

   [SerializeField] private CollisionItem m_Weakness;

   public bool IsWinner(CollisionItem other)
   {
       return other.m_Weakness == this;
   }
}

Lợi ích của kiểu liệt kê dựa trên ScriptableObject

Khi đã quen thuộc với các kiểu liệt kê dựa trên ScriptableObject, bạn sẽ thấy chúng có thể cải thiện quy trình làm việc của mình, đặc biệt là khi làm việc với đồng đội. Vì chúng là các tài sản, việc cập nhật chúng sẽ tạo ra ít xung đột khi hợp nhất hơn, giảm nguy cơ mất dữ liệu.

Việc thêm các kiểu liệt kê dựa trên ScriptableObject mới cũng giống như việc tạo một tài nguyên khác. Khác với kiểu liệt kê truyền thống, việc thêm giá trị mới sẽ không làm hỏng mã hiện có của bạn. Thêm vào đó, Unity đã tích hợp sẵn các công cụ để tìm kiếm, bộ lọc và sắp xếp chúng, giống như bất kỳ tài nguyên nào khác.

Thêm vào đó, giao diện kéo và thả của Trình chỉnh sửa cho phép các nhà thiết kế mở rộng dữ liệu trò chơi mà không cần sự hỗ trợ thêm từ nhà phát triển phần mềm. Ban đầu bạn vẫn cần phối hợp cách thiết lập các trường thông tin, nhưng sau đó các nhà thiết kế có thể tự điền dữ liệu vào các trường đó.

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

Thêm tài nguyên ScriptableObject

Các kiểu liệt kê dựa trên ScriptableObject là một nguồn lực nữa mà nhóm của bạn có thể sử dụng để cải thiện sự hợp tác và hiệu quả.

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" .