Thành phần nhân vật trong trò chơi
Thuộc phần Lập trình hướng đối tượng trong hành trình C# của Coddy. Bài học 69 trên 70.
Thử thách
DễHãy xây dựng một hệ thống nhân vật trong trò chơi bằng mẫu kiến trúc dựa trên thành phần! Thay vì tạo các hệ phân cấp kế thừa cứng nhắc, bạn sẽ kết hợp các nhân vật bằng cách gắn những thành phần độc lập, mỗi thành phần xử lý một hành vi cụ thể. Đây là cách tiếp cận linh hoạt được sử dụng rộng rãi trong phát triển trò chơi.
Bạn sẽ sắp xếp code trong năm tệp:
IComponent.cs: Định nghĩa một giao diệnIComponenttrong không gian tênGame.Components. Mỗi thành phần phải có phương thứcUpdate()để in ra hoạt động của thành phần.HealthComponent.cs: Tạo lớpHealthComponenttriển khaiIComponent. Lớp này cần theo dõi điểm máu hiện tại và tối đa, cùng các phương thứcTakeDamage(int amount)vàHeal(int amount). Điểm máu không bao giờ được thấp hơn 0 hoặc cao hơn mức tối đa. Thêm sự kiệnevent Action<int> HealthChanged, được kích hoạt mỗi khi điểm máu thay đổi và truyền giá trị điểm máu mới. Phương thứcUpdate()cần in ra trạng thái điểm máu hiện tại.InventoryComponent.cs: Tạo lớpInventoryComponenttriển khaiIComponent. Lớp này quản lý danh sách tên vật phẩm với các phương thứcAddItem(string item)vàRemoveItem(string item)(trả vềboolđể cho biết thao tác có thành công hay không). Phương thứcUpdate()cần in ra nội dung túi đồ.Character.cs: Tạo lớpCharactertrong không gian tênGame, lớp này lưu một tập hợp các thành phần. Nhân vật cần có thuộc tínhNamevà các phương thức sau:AddComponent(IComponent component)- gắn một thành phần vào nhân vậtGetComponent<T>()với điều kiện T : IComponent - trả về thành phần đầu tiên thuộc kiểu T hoặc null nếu không tìm thấyUpdateAll()- gọiUpdate()trên từng thành phần đã gắn
Program.cs: Kết hợp mọi thứ bằng cách tạo một nhân vật, gắn các thành phần và xử lý lệnh.
Bạn sẽ nhận các đầu vào sau:
- Tên nhân vật
- Điểm máu tối đa ban đầu cho HealthComponent
- Số lệnh cần xử lý
- Với mỗi lệnh: hành động, theo sau là dữ liệu liên quan
Định dạng lệnh:
damage
{amount}
heal
{amount}
add_item
{itemName}
remove_item
{itemName}
updateĐịnh dạng đầu ra:
- Khi điểm máu thay đổi (thông qua sự kiện):
Health changed: {newHealth} - Khi thêm vật phẩm:
Added: {itemName} - Khi xóa vật phẩm:
Removed: {itemName}hoặcItem not found: {itemName} - Phương thức
Update()của HealthComponent:Health: {current}/{max} - Phương thức
Update()của InventoryComponent:Inventory: {item1}, {item2}, ...hoặcInventory: empty
Ví dụ, nếu đầu vào là:
Hero
100
7
add_item
Sword
add_item
Shield
damage
30
heal
10
remove_item
Potion
remove_item
Sword
updateĐầu ra sẽ là:
Added: Sword
Added: Shield
Health changed: 70
Health changed: 80
Item not found: Potion
Removed: Sword
Health: 80/100
Inventory: ShieldHãy chú ý rằng nhân vật không kế thừa từ lớp đặc biệt nào, mà chỉ lưu các thành phần cung cấp hành vi. Phương thức GetComponent<T>() dùng kiểu tổng quát để truy xuất an toàn theo kiểu, còn các sự kiện thông báo khi điểm máu thay đổi. Cách kết hợp này cho phép bạn tự do phối hợp các thành phần!
Tự làm thử
using System;
using Game;
using Game.Components;
class Program
{
public static void Main(string[] args)
{
// Đọc tên nhân vật
string characterName = Console.ReadLine();
// Đọc mức máu tối đa ban đầu
int maxHealth = Convert.ToInt32(Console.ReadLine());
// Đọc số lượng lệnh
int numCommands = Convert.ToInt32(Console.ReadLine());
// TODO: Tạo Character với tên đã cho
// TODO: Tạo HealthComponent với maxHealth và InventoryComponent
// TODO: Đăng ký sự kiện HealthChanged để in ra: Health changed: {newHealth}
// TODO: Thêm cả hai thành phần vào nhân vật
// TODO: Xử lý từng lệnh
for (int i = 0; i < numCommands; i++)
{
string command = Console.ReadLine();
// TODO: Xử lý từng loại lệnh:
// - "damage": đọc lượng, gọi TakeDamage trên thành phần máu
// - "heal": đọc lượng, gọi Heal trên thành phần máu
// - "add_item": đọc tên vật phẩm, gọi AddItem trên thành phần kho đồ
// - "remove_item": đọc tên vật phẩm, gọi RemoveItem trên thành phần kho đồ
// - "update": gọi UpdateAll trên nhân vật
}
}
}
Tất cả bài học trong Lập trình hướng đối tượng
1Các khái niệm cơ bản về lập trình hướng đối tượng
Tệp bên ngoàiKhông gian tên và chỉ thịGiới thiệu về lớp và đối tượngTừ khóa thisPhương thức và tham sốTrường và thuộc tínhHàm khởi tạoKhởi tạo đối tượngÔn tập: Máy tính đơn giản4Kế thừa
Cú pháp kế thừa cơ bản (:)Từ khóa 'base'Từ khóa virtual và overrideLớp sealedLớp cơ sở 'object'Ôn tập: hệ phân cấp nhân viên7Tính năng nâng cao
Nạp chồng toán tửBộ lập chỉ mục (this[])Ghi đè ToString()Phương thức mở rộngÔn tập: Danh sách tùy chỉnh10Các mẫu thiết kế phần 1
Giới thiệu về mẫu thiết kếSingleton an toàn với luồngMẫu FactoryMẫu Observer (sự kiện)Mẫu Strategy13Thử thách cuối
Nền tảng học trực tuyếnThành phần nhân vật trong trò chơiDịch vụ cho thuê phương tiện2Thuộc tính và thành viên tĩnh
Thuộc tính tự độngThuộc tính chỉ đọc hoặc chỉ ghiTrường và phương thức tĩnhLớp tĩnhThành viên có thân biểu thức5Đa hình và interface
Đa hình lúc biên dịch và lúc chạyInterface và lớp trừu tượngNhiều interfaceInterface tường minhUpcasting và downcastingÔn tập: bộ tính toán hình học8Các khái niệm OOP nâng cao
Ưu tiên composition hơn kế thừaGenerics (lớp và phương thức)Delegate và sự kiệnAttribute và reflectionGiao diện IDisposable và câu lệnh usingKiến thức cơ bản về dependency injection11Các mẫu thiết kế phần 2
Mẫu lệnhMẫu bộ chuyển đổiMẫu trang tríMẫu phương thức khuôn mẫuMẫu trạng tháiMẫu tổ hợpTự luyện tập: Trình biên dịch C# online