Ghi đè hành vi thành phần


7

Tôi đã nghĩ về cách thực hiện ghi đè các hành vi trong một hệ thống thực thể dựa trên thành phần. Một ví dụ cụ thể, một thực thể có thành phần sức khỏe có thể bị hư hại, được chữa lành, bị giết, v.v ... Thực thể đó cũng có một thành phần áo giáp giới hạn mức độ thiệt hại mà nhân vật nhận được.

Có ai đã thực hiện các hành vi như thế này trong một hệ thống dựa trên thành phần trước đây chưa?
Bạn đã làm nó như thế nào?

Nếu không ai từng làm điều này trước đây tại sao bạn nghĩ đó là. Có bất cứ điều gì đặc biệt sai lầm về việc ghi đè các hành vi thành phần?

Dưới đây là bản phác thảo sơ bộ về cách tôi tưởng tượng nó sẽ hoạt động. Các thành phần trong một thực thể được đặt hàng. Những người ở phía trước có cơ hội để phục vụ một giao diện đầu tiên. Tôi không nói chi tiết về việc đó được thực hiện như thế nào, chỉ giả sử nó sử dụng tà ác dynamic_cast(không có nhưng hiệu quả cuối cùng là như nhau mà không cần RTTI).

class IHealth
{
public:
   float get_health( void ) const = 0;
   void do_damage( float amount ) = 0;
};

class Health : public Component, public IHealth
{
public:
   void do_damage( float amount )
   {
      m_damage -= amount;
   }
private:
   float m_health;
};

class Armor : public Component, public IHealth
{
public:
   float get_health( void ) const
   {
      return next<IHealth>().get_health();
   }

   void do_damage( float amount )
   {
      next<IHealth>().do_damage( amount / 2 );
  }
};

entity.add( new Health( 100 ) );
entity.add( new Armor() );
assert( entity.get<IHealth>().get_health() == 100 );
entity.get<IHealth>().do_damage( 10 );
assert( entity.get<IHealth>().get_health() == 95 );

Có điều gì đặc biệt ngây thơ về cách tôi đề xuất để làm điều này?


Xin vui lòng xem câu trả lời của tôi ở đây: gamedev.stackexchange.com/questions/13916/ . Nếu liên kết đến một câu trả lời của riêng bạn được tán thành, xin vui lòng mod loại bỏ điều này.
Raine

2
Có lý do cụ thể nào khiến bạn tạo giao diện bổ sung cho IHealth và sau đó sử dụng nhiều quyền thừa kế hơn nữa thay vì thừa kế IHealth từ Thành phần và sau đó chỉ có Giáp và Sức khỏe được thừa hưởng từ IHealth không?
TravisG

@heishe: Tôi đã lo lắng rằng một thành phần có thể muốn thực hiện hai giao diện khác nhau, tức là IHealthIKnockback. Sẽ không có nghĩa gì nếu tham gia hai thành phần đó trong một hệ thống phân cấp lớp duy nhất. Nhiều kế thừa luôn gây rắc rối Tôi đã cân nhắc việc Shield sử dụng một lớp thành viên proxy xuất phát từ IHealthđó và sau đó chuyển tiếp tất cả các cuộc gọi đến Shield. Với kỹ thuật triển khai đó, không có MI với chi phí của một cuộc gọi phương thức phi ảo bổ sung (mà trình tối ưu hóa có thể có khả năng nội tuyến). Trong cả hai trường hợp API ( add, get, next, vv) là như nhau.
deft_code

Câu trả lời:


3

Tôi nghĩ rằng bạn đang làm cho nó quá phức tạp hoặc không đủ phức tạp.

Một hướng tôi muốn đề xuất là phá vỡ sức khỏe và gây sát thương.

Vì vậy, có thể như một ý tưởng, thành phần Armor của bạn sẽ trông như thế này:

class Armor : public Component, public IDamageReceiver
{
public:
   void do_damage( float amount )
   {
      // just assume that subtract_health isn't used in client code maybe
      this.get<IHealth>().subtract_health( amount / 2 ); 
   }
};

Ngoài ra (và có lẽ những gì tôi sẽ làm), bạn có thể làm cho các thành phần của mình lớn hơn một chút và chỉ cần có một lớp cơ sở "Thực thể" chung chung mà các loại cụ thể của bạn xuất phát từ đó. Điều này sẽ chứa chức năng của cả sức khỏe và áo giáp và bạn có thể thực hiện các thực thể cụ thể từ đó.


Giải pháp của bạn không giải quyết được vấn đề của tôi. Tôi muốn thêm thành phần Armor mà không cần điều chỉnh bất kỳ thành phần nào có sẵn. Hoàn thành đúng, tôi nghĩ bạn chỉ cần thêm hai thành phần áo giáp và nó sẽ làm đúng (giảm sát thương xuống 25%). Nói cách khác với một giải pháp ghi đè chung, tôi có thể ghi đè các phần ghi đè.
deft_code

3
Tôi đồng ý với Tetrad ở đây. Tôi nghĩ rằng bạn đang làm cho hệ thống của bạn quá phức tạp và chi tiết. Tôi sẽ nói nếu bạn muốn ghi đè thành phần X, hãy tìm thành phần X trong các thực thể có liên quan và trao đổi nó với thành phần Y thực hiện những gì bạn muốn.

1
@deft_code Dựa trên những gì bạn đã nói và bài đăng khác của bạn về các thành phần trước bài này. Tôi nghĩ rằng bạn muốn giới thiệu một loại 'Nhân vật đặc trưng' (không sử dụng tăng sức mạnh vì đôi khi chúng có thể xấu :)) loại thành phần mà bạn có thể tạo (de) buff để áp dụng cho nhân vật. Điều này vẫn sẽ yêu cầu cập nhật thành phần sức khỏe để quét các hiệu ứng liên quan để xem có áp dụng hay không, nhưng cần phải có một loại thành phần mới thay vì thừa hưởng sức khỏe và Không thay thế sức khỏe. Thay phiên, làm cho hệ thống thành phần của bạn có một ngăn xếp để có thứ tự thực hiện / giải quyết được đảm bảo.
James

2

Suy nghĩ của bạn đang ở đúng chỗ nhưng tôi nghĩ bạn đang cố gắng đưa hệ thống thành phần đến một mức độ chi tiết mà nó không cần. Tôi muốn nói hãy tạo ra một thành phần gọi là Sức khỏe khi tất cả những gì bạn cần là sức khỏe. Nhưng nếu bạn cần một thành phần sức khỏe cũng có áo giáp, thì hãy biến nó thành thành phần CHealthAndArmor vẫn phù hợp với API của Sức khỏe nói chung để nó có thể được sử dụng như bất kỳ loại nào khác, nhưng sau đó cung cấp cách thay đổi cấp độ áo giáp nếu cần thiết .. Nếu nó hoàn toàn là một giá trị thời gian tải thì không cần, đó chỉ là hoạt động bên trong của thành phần sức khỏe cụ thể đó.

Thành thật mà nói, mối quan tâm của bạn (từ bài này và bài khác của bạn) là mức độ chi tiết bạn chia nhỏ thành phần tốt đến mức nào. Nếu bạn thấy mình kế thừa hoặc gói gọn một thành phần trong một thành phần khác, bạn nên xem xét lại những gì bạn đang làm. Bạn thường đang cố gắng tránh sự kế thừa như thế này trong các kiến ​​trúc dựa trên thành phần.

Hi vọng điêu nay co ich


1
Tạo một loại thành phần HealthAndArmor đánh bại mục đích của kiến ​​trúc dựa trên thành phần.
Mitchell

@Mitchell Điều đó phụ thuộc vào trò chơi thực sự. Nếu áo giáp của bạn không có gì nhiều ngoài sức khỏe như trong các trò chơi kiểu Doom / Quake cũ thì việc tách những thứ này ra sẽ là một sự lãng phí hoàn toàn. Các thành phần của bạn phải phù hợp với môi trường và trò chơi của bạn.
James

Tôi không đồng ý, việc phân tách chúng cho phép sửa đổi dễ dàng trong tương lai và việc thay đổi từ 'áo giáp và sức khỏe' thành 'sức khỏe' chỉ yêu cầu loại bỏ áo giáp, thay vì loại bỏ HealthAndArmor và thêm Sức khỏe. Nó có vẻ không đáng kể, nhưng nó có thể trở nên thực sự khó chịu khi bạn tạo mẫu nhiều. Nhưng tôi đoán nó cũng phụ thuộc vào người quản lý thực thể của bạn.
Mitchell

@Mitchell Tôi đoán rằng chúng ta sẽ phải không đồng ý sau đó .. Tôi đã luôn xem các thành phần như một cái gì đó mà bạn điều chỉnh cho trò chơi / ứng dụng trong câu hỏi. Chắc chắn bạn thu thập được một bộ sưu tập tốt đẹp theo thời gian tùy thuộc vào số lượng dự án bạn sử dụng / tái sử dụng hệ thống, nhưng toàn bộ điểm của hệ thống thành phần đối với tôi là tạo ra các đối tượng phức tạp hơn từ các đối tượng nhỏ hơn và đơn giản.
James


0

Tôi sử dụng một hệ thống thành phần hướng sự kiện và có vấn đề tương tự. Về cơ bản tôi đăng ký các chức năng thành phần cho các sự kiện thành phần khác. Đối với một sự kiện tôi có thể có x chức năng được đăng ký và các sự kiện được kích hoạt theo thứ tự chúng đã được đăng ký. Các sự kiện cũng đưa ra một tham số là một lớp động và được truyền bằng tham chiếu. Tất cả điều này có nghĩa là tôi có thể tạo thành phần Thống kê và thành phần Sức khỏe. Tôi đăng ký cả hai vào một thông điệp bị tổn thương nhưng vì Thống kê được đăng ký trước nên nó sẽ sử dụng chỉ số giáp của thành phần Stat và sửa đổi giá trị thiệt hại bên trong đối tượng tham số. Thành phần sức khỏe tiếp theo trong danh sách đăng ký và tại thời điểm nó được gọi là giá trị thiệt hại đã được giảm.

Tôi không thể nói đủ về cách thức xử lý các sự kiện. Nó thực sự cho phép chắp nối các chức năng thông qua các thành phần mà chúng không biết về nhau. Người dùng chỉ cần thiết lập các đăng ký sự kiện để xây dựng chức năng. Sẽ không bao giờ nhìn lại từ hệ thống này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.