Thành phần trừu tượng
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 3 trên 64.
Một số lớp cơ sở mô tả một loại đối tượng không bao giờ tồn tại độc lập. Mọi vũ khí đều khai hỏa, nhưng một vũ khí không phải súng lục hay súng săn thì không có cách nào để khai hỏa. Đánh dấu lớp như vậy là abstract, rồi khai báo mỗi bước mà lớp con phải viết thành một phương thức trừu tượng, không có phần thân:
public abstract class Weapon : MonoBehaviour
{
public int shots;
public void Pull()
{
shots++;
Fire();
}
protected abstract void Fire();
}public class Shotgun : Weapon
{
public GameObject pelletPrefab;
protected override void Fire()
{
for (int i = -1; i <= 1; i++)
{
Instantiate(pelletPrefab, transform.position + transform.right * i * 0.3f, transform.rotation);
}
}
}Lớp con không viết Fire sẽ không biên dịch được: CS0534, 'Pistol' does not implement inherited abstract member 'Weapon.Fire()'. Unity cũng không cho phép gắn một script trừu tượng vào đối tượng. Kéo Weapon vào đối tượng, bạn sẽ thấy thông báo Can't add script behaviour 'Weapon'. The script class can't be abstract!, vì Unity không thể tạo một Weapon không có Fire.
Các script khác vẫn hoạt động với kiểu cơ sở. GetComponent<Weapon>() trả về lớp con đang gắn trên đối tượng, còn Pull() chạy Fire của lớp con đó:
// Player.cs
private Weapon weapon;
void Start()
{
weapon = GetComponent<Weapon>();
}
void Update()
{
if (Mouse.current.leftButton.wasPressedThisFrame)
{
weapon.Pull();
}
}Thay thành phần Shotgun bằng Pistol, script Player vẫn giữ nguyên.
Thử thách
DễBiến Monster thành lớp trừu tượng để tháp đánh mọi loại quái vật.
- Trong
Monster, viếtpublic abstract class Monstervàprotected abstract void React();, không có phần thân. - Giờ trình biên dịch sẽ chỉ ra lỗi ở
Imp: thêmprotected override void React()để cộngVector3.forward * 2fvào vị trí của nó. - Trong
Tower, bên trong vòng lặp, gọiZap()trêntarget.GetComponent<Monster>().
Nhấn Chơi rồi nhấn phím cách: slime sẽ co nhỏ, imp sẽ nhảy lùi lại. Sau đó nhấn Kiểm tra.
Tự làm thử
using UnityEngine;
// Đặc điểm chung của mọi quái vật.
public class Monster : MonoBehaviour
{
public int hp = 3;
public void Zap()
{
hp--;
if (hp <= 0)
{
Destroy(gameObject);
}
else
{
React();
}
}
// Cách loại quái vật này phản ứng sau khi trúng đòn điện mà vẫn sống.
protected virtual void React()
{
}
}
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