Mục đích của tôi là tạo ra một hệ thống vật phẩm mô đun / chung chung nhất có thể để xử lý những việc như:
- Vật phẩm có thể nâng cấp (+6 Katana)
- Công cụ điều chỉnh Stat (+15 khéo léo)
- Công cụ sửa đổi vật phẩm (% X cơ hội gây sát thương Y, cơ hội đóng băng)
- Vật phẩm có thể sạc lại (Nhân viên ma thuật với 30 lần sử dụng)
- Đặt Mục (Trang bị 4 phần X được đặt để kích hoạt tính năng Y)
- Hiếm khi (phổ biến, độc đáo, huyền thoại)
- Không thể tháo rời (đột nhập vào một số vật liệu chế tạo)
- Craftable (có thể được chế tạo bằng vật liệu nhất định)
- Tiêu hao (5 phút% sức tấn công X, hồi máu +15 hp)
* Tôi đã có thể giải quyết các tính năng được in đậm trong thiết lập sau.
Bây giờ tôi đã cố gắng thêm nhiều tùy chọn để phản ánh những gì tôi có trong đầu. Tôi không có kế hoạch thêm tất cả các tính năng cần thiết này, nhưng tôi muốn có thể triển khai chúng khi tôi thấy phù hợp. Chúng cũng phải tương thích với hệ thống kiểm kê và tuần tự hóa dữ liệu.
Tôi dự định hoàn toàn không sử dụng kế thừa mà thay vào đó là cách tiếp cận dựa trên dữ liệu thành phần / thực thể. Ban đầu tôi nghĩ về một hệ thống có:
- BaseStat: một lớp chung chứa các số liệu thống kê khi đang di chuyển (cũng có thể được sử dụng cho các mục và thống kê nhân vật)
- Item: một lớp chứa dữ liệu như danh sách, tên, itemtype và những thứ có liên quan đến ui, actionName, mô tả, v.v.
- IWeapon: giao diện cho vũ khí. Mỗi vũ khí sẽ có lớp riêng với IWeapon được triển khai. Điều này sẽ có Tấn công và tham chiếu đến chỉ số nhân vật. Khi vũ khí được trang bị, dữ liệu của nó (chỉ số của lớp vật phẩm) sẽ được đưa vào chỉ số nhân vật (bất kể BaseStat nào, nó sẽ được thêm vào lớp nhân vật dưới dạng phần thưởng Stat) Vì vậy, ví dụ, chúng tôi muốn tạo ra một thanh kiếm (nghĩ đến tạo các lớp vật phẩm với json) vì vậy thanh kiếm sẽ thêm 5 đòn tấn công vào chỉ số nhân vật. Vì vậy, chúng tôi có BaseStat là ("Tấn công", 5) (chúng tôi cũng có thể sử dụng enum). Chỉ số này sẽ được thêm vào chỉ số "Tấn công" của nhân vật dưới dạng BonusStat (sẽ là một lớp khác) khi trang bị nó. Vì vậy, một lớp có tên Sword thực hiện IWeapon sẽ được tạo khi nó 'Lớp vật phẩm được tạo ra. Vì vậy, chúng ta có thể tiêm các chỉ số nhân vật vào thanh kiếm này và khi tấn công, nó có thể lấy tổng chỉ số Tấn công từ chỉ số nhân vật và gây sát thương trong phương thức Tấn công.
- BonusStat: là cách thêm số liệu thống kê dưới dạng tiền thưởng mà không cần chạm vào BaseStat.
- IConsumable: Logic tương tự như với IWeapon. Thêm chỉ số trực tiếp khá dễ dàng (+15 hp) nhưng tôi không chắc chắn về việc thêm vũ khí tạm thời với thiết lập này (% x để tấn công trong 5 phút).
- IUpgradizable: Điều này có thể được thực hiện với thiết lập này. Tôi đang nghĩ Nâng cấp như một chỉ số cơ bản, được tăng lên khi nâng cấp vũ khí. Khi được nâng cấp, chúng ta có thể tính lại BaseStat của vũ khí để phù hợp với cấp độ Nâng cấp của nó.
Cho đến thời điểm này, tôi có thể thấy hệ thống đó khá tốt. Nhưng đối với các tính năng khác, tôi nghĩ rằng chúng tôi cần một cái gì đó khác, vì ví dụ tôi không thể triển khai tính năng Craftable vào điều này vì BaseStat của tôi sẽ không thể xử lý tính năng này và đây là nơi tôi gặp khó khăn. Tôi có thể thêm tất cả các thành phần dưới dạng Stat nhưng điều đó sẽ không có ý nghĩa.
Để giúp bạn dễ dàng đóng góp điều này, đây là một số câu hỏi mà bạn có thể giúp đỡ:
- Tôi có nên tiếp tục với thiết lập này để thực hiện các tính năng khác? Nó sẽ có thể mà không cần thừa kế?
- Có cách nào bạn có thể nghĩ ra, để thực hiện tất cả các tính năng này mà không cần kế thừa không?
- Về sửa đổi vật phẩm, làm thế nào người ta có thể đạt được điều đó? Bởi vì nó rất chung chung trong bản chất của nó.
- Có thể làm gì để giảm bớt quá trình xây dựng loại kiến trúc này, có khuyến nghị nào không?
- Có nguồn nào tôi có thể đào có liên quan đến vấn đề này không?
- Tôi thực sự cố gắng tránh thừa kế, nhưng bạn có nghĩ rằng những điều này sẽ được giải quyết / đạt được với sự kế thừa một cách dễ dàng trong khi vẫn giữ nó khá bền?
Hãy trả lời chỉ một câu hỏi vì tôi giữ câu hỏi rất rộng để tôi có thể nhận được kiến thức từ các khía cạnh / người khác nhau.
BIÊN TẬP
Theo câu trả lời của @ jjimenezg93, tôi đã tạo ra một hệ thống rất cơ bản trong C # để thử nghiệm, nó hoạt động! Xem nếu bạn có thể thêm bất cứ điều gì vào nó:
public interface IItem
{
List<IAttribute> Components { get; set; }
void ReceiveMessage<T>(T message);
}
public interface IAttribute
{
IItem source { get; set; }
void ReceiveMessage<T>(T message);
}
Cho đến nay, IItem và IAttribution là các giao diện cơ bản. Không có nhu cầu (mà tôi có thể nghĩ ra) để có một giao diện / thuộc tính cơ bản cho tin nhắn, vì vậy chúng tôi sẽ trực tiếp tạo một lớp thông báo thử nghiệm. Bây giờ cho các lớp kiểm tra:
public class TestItem : IItem
{
private List<IAttribute> _components = new List<IAttribute>();
public List<IAttribute> Components
{
get
{
return _components;
}
set
{
_components = value;
}
}
public void ReceiveMessage<T>(T message)
{
foreach (IAttribute attribute in Components)
{
attribute.ReceiveMessage(message);
}
}
}
public class TestAttribute : IAttribute
{
string _infoRequiredFromMessage;
public TestAttribute(IItem source)
{
_source = source;
}
private IItem _source;
public IItem source
{
get
{
return _source;
}
set
{
_source = value;
}
}
public void ReceiveMessage<T>(T message)
{
TestMessage convertedMessage = message as TestMessage;
if (convertedMessage != null)
{
convertedMessage.Execute();
_infoRequiredFromMessage = convertedMessage._particularInformationThatNeedsToBePassed;
Debug.Log("Message passed : " + _infoRequiredFromMessage);
}
}
}
public class TestMessage
{
private string _messageString;
private int _messageInt;
public string _particularInformationThatNeedsToBePassed;
public TestMessage(string messageString, int messageInt, string particularInformationThatNeedsToBePassed)
{
_messageString = messageString;
_messageInt = messageInt;
_particularInformationThatNeedsToBePassed = particularInformationThatNeedsToBePassed;
}
//messages should not have methods, so this is here for fun and testing.
public void Execute()
{
Debug.Log("Desired Execution Method: \nThis is test message : " + _messageString + "\nThis is test int : " + _messageInt);
}
}
Đây là những thiết lập cần thiết. Bây giờ chúng tôi có thể sử dụng hệ thống (Sau đây là cho Unity).
public class TestManager : MonoBehaviour
{
// Use this for initialization
void Start()
{
TestItem testItem = new TestItem();
TestAttribute testAttribute = new TestAttribute(testItem);
testItem.Components.Add(testAttribute);
TestMessage testMessage = new TestMessage("my test message", 1, "VERYIMPORTANTINFO");
testItem.ReceiveMessage(testMessage);
}
}
Đính kèm tập lệnh TestManager này vào một thành phần trong cảnh và bạn có thể thấy trong gỡ lỗi thông báo đó được truyền thành công.
Để giải thích mọi thứ: Mọi vật phẩm trong trò chơi sẽ triển khai giao diện IItem và mọi Thuộc tính (tên không nên làm bạn bối rối, điều đó có nghĩa là tính năng / hệ thống vật phẩm. Giống như Nâng cấp hoặc không thể gỡ bỏ) sẽ triển khai IAttribution. Sau đó, chúng tôi có một phương pháp để xử lý tin nhắn (tại sao chúng tôi cần tin nhắn sẽ được giải thích trong ví dụ tiếp theo). Vì vậy, trong ngữ cảnh, bạn có thể đính kèm các thuộc tính cho một mục và để phần còn lại làm cho bạn. Điều này rất linh hoạt, bởi vì bạn có thể thêm / xóa các thuộc tính một cách dễ dàng. Vì vậy, một ví dụ giả sẽ không thể chấp nhận được. Chúng ta sẽ có một lớp gọi là Disenchantable (IAttribution) và nó theo phương thức Disenchant, nó sẽ yêu cầu:
- Liệt kê các thành phần (khi vật phẩm bị loại bỏ, vật phẩm nào nên được cung cấp cho người chơi) lưu ý: IItem nên được mở rộng để có ItemType, ItemID, v.v.
- int resultModifier (nếu bạn triển khai một loại tăng tính năng khử mùi, bạn có thể chuyển một int ở đây để tăng các thành phần nhận được khi bị loại bỏ)
- int failChance (nếu quá trình không hài lòng có cơ hội thất bại)
Vân vân.
Những thông tin này sẽ được cung cấp bởi một lớp có tên DisenchantManager, nó sẽ nhận được vật phẩm và hình thành thông báo này theo vật phẩm (thành phần của vật phẩm khi bị loại bỏ) và tiến trình của người chơi (resultModifier và failChance). Để truyền thông điệp này, chúng tôi sẽ tạo một lớp DisenchantMessage, lớp này sẽ hoạt động như một cơ thể cho thông điệp này. Vì vậy, DisenchantManager sẽ đưa vào DisenchantMessage và gửi nó đến vật phẩm. Mục sẽ nhận được thông báo và chuyển nó đến tất cả các Thuộc tính được đính kèm. Vì phương thức receiveMessage của lớp Disenchantable sẽ tìm kiếm DisenchantMessage, nên chỉ có thuộc tính Disenchantable mới nhận được thông báo này và hành động theo nó. Hy vọng điều này sẽ xóa mọi thứ nhiều như nó đã làm cho tôi :).