Các thành phần vật lý hoặc đồ họa thường được xây dựng trong một hệ thống định hướng thành phần như thế nào?


19

Tôi đã dành 48 giờ qua để đọc các hệ thống Thành phần đối tượng và cảm thấy tôi đã sẵn sàng để bắt đầu thực hiện nó. Tôi đã tạo các lớp Đối tượng và Thành phần cơ bản được tạo, nhưng bây giờ tôi cần bắt đầu tạo các thành phần thực tế, tôi hơi bối rối. Khi tôi nghĩ về chúng theo HealthComponent hoặc thứ gì đó về cơ bản chỉ là một tài sản, nó có ý nghĩa hoàn hảo. Khi nó là một cái gì đó tổng quát hơn như là một thành phần Vật lý / Đồ họa, tôi có một chút bối rối.

Lớp Object của tôi trông như thế này cho đến nay (Nếu bạn nhận thấy bất kỳ thay đổi nào tôi nên thực hiện, vui lòng cho tôi biết, vẫn còn mới đối với điều này) ...

typedef unsigned int ID;

class GameObject
{
public:

    GameObject(ID id, Ogre::String name = "");
    ~GameObject();

    ID &getID();
    Ogre::String &getName();

    virtual void update() = 0;

    // Component Functions
    void addComponent(Component *component);
    void removeComponent(Ogre::String familyName);

    template<typename T>
    T* getComponent(Ogre::String familyName)
    {
        return dynamic_cast<T*>(m_components[familyName]);
    }

protected:

    // Properties
    ID m_ID;
    Ogre::String m_Name;
    float m_flVelocity;
    Ogre::Vector3 m_vecPosition;

    // Components
    std::map<std::string,Component*> m_components;
    std::map<std::string,Component*>::iterator m_componentItr;
};

Bây giờ vấn đề tôi đang gặp phải là dân số nói chung sẽ đưa gì vào các Thành phần như Vật lý / Đồ họa? Đối với Ogre (công cụ kết xuất của tôi), các Đối tượng hiển thị sẽ bao gồm nhiều Ogre :: SceneNode (có thể là nhiều) để gắn nó vào cảnh, Ogre :: Entity (có thể là nhiều) để hiển thị các lưới có thể nhìn thấy, v.v. Sẽ là tốt nhất khi chỉ cần thêm nhiều GraphicComponent vào Object và để mỗi GraphicComponent xử lý một SceneNode / Entity hoặc ý tưởng cần có một trong mỗi Thành phần cần thiết?

Đối với môn Vật lý tôi lại càng bối rối hơn. Tôi cho rằng có thể tạo RigidBody và theo dõi khối lượng / interia / vv. sẽ có ý nghĩa Nhưng tôi gặp khó khăn khi nghĩ làm thế nào để thực sự đưa chi tiết cụ thể vào Thành phần.

Khi tôi nhận được một vài thành phần "Bắt buộc" này, tôi nghĩ nó sẽ có ý nghĩa hơn nhiều. Ngay bây giờ mặc dù tôi vẫn còn hơi bối rối.

Câu trả lời:


32

Trước hết, khi bạn xây dựng các hệ thống dựa trên thành phần, bạn không phải thực hiện phương pháp biến mọi thứ thành một thành phần. Trên thực tế, bạn thường không nên - đó là một lỗi của người mới. Theo kinh nghiệm của tôi, cách tốt nhất để gắn kết các hệ thống kết xuất và vật lý trong một kiến ​​trúc dựa trên thành phần là làm cho các thành phần đó ít hơn các thùng chứa câm cho đối tượng nguyên thủy kết xuất hoặc vật lý.

Điều này có thêm lợi thế là giữ cho các hệ thống kết xuất và vật lý tách rời khỏi hệ thống thành phần.

Ví dụ, đối với các hệ thống vật lý, trình mô phỏng vật lý thường giữ một danh sách lớn các vật thể cứng mà nó thao tác mỗi khi nó chạm vào. Hệ thống thành phần của bạn không gây rắc rối với điều đó - thành phần vật lý của bạn chỉ lưu trữ một tham chiếu đến cơ thể cứng nhắc đại diện cho các khía cạnh vật lý của đối tượng và chuyển bất kỳ thông điệp nào từ hệ thống thành phần thành các thao tác thích hợp của cơ thể cứng nhắc.

Tương tự như vậy với kết xuất - trình kết xuất của bạn sẽ có một cái gì đó đại diện cho dữ liệu cá thể được hiển thị và thành phần trực quan của bạn chỉ đơn giản giữ một tham chiếu đến đó.

Điều đó tương đối đơn giản - vì bất kỳ lý do gì nó dường như gây nhầm lẫn cho mọi người, nhưng điều đó thường là do họ đang nghĩ về nó quá khó. Không có nhiều phép thuật ở đó. Và vì điều quan trọng nhất là hoàn thành công việc thay vì thống nhất thiết kế hoàn hảo, bạn nên cân nhắc mạnh mẽ cách tiếp cận trong đó ít nhất một số thành phần đã xác định giao diện và là thành viên trực tiếp của đối tượng trò chơi, như momboco đã đề xuất. Đó chỉ là một cách tiếp cận hợp lệ và nó có xu hướng dễ dàng hơn để tìm kiếm.

Những bình luận khác

Điều này không liên quan đến câu hỏi trực tiếp của bạn, nhưng đây là những điều tôi nhận thấy khi xem mã của bạn:

Tại sao bạn trộn Ogre :: String và std :: string trong đối tượng trò chơi của bạn, có vẻ như là một đối tượng không có đồ họa và do đó không nên có sự phụ thuộc vào Ogre? Tôi sẽ đề nghị xóa tất cả các tham chiếu trực tiếp đến Ogre ngoại trừ trong chính thành phần kết xuất, nơi bạn nên thực hiện chuyển đổi.

update () là một ảo thuần, ngụ ý rằng người ta phải phân lớp GameObject, đây thực sự là loại hoàn toàn ngược lại với hướng bạn muốn đi với kiến ​​trúc thành phần. Điểm chính của việc sử dụng các thành phần là thích tổng hợp chức năng hơn là kế thừa.

Bạn có thể hưởng lợi từ việc sử dụng const(cụ thể là nơi bạn sẽ quay lại bằng cách tham khảo). Ngoài ra tôi không chắc chắn rằng bạn thực sự muốn vận tốc là một vô hướng (hoặc nếu nó, và vị trí, nên có mặt trong đối tượng trò chơi theo kiểu phương pháp thành phần quá chung chung mà bạn dường như sẽ thực hiện).

Cách tiếp cận của bạn về việc sử dụng bản đồ lớn các thành phần và update()cuộc gọi trong đối tượng trò chơi là khá tối ưu (và một cạm bẫy chung cho những người đầu tiên xây dựng các loại hệ thống này). Nó tạo ra sự đồng bộ bộ đệm rất kém trong quá trình cập nhật và không cho phép bạn tận dụng lợi thế đồng thời và xu hướng xử lý theo kiểu SIMD của các lô dữ liệu hoặc hành vi lớn cùng một lúc. Tốt hơn là nên sử dụng một thiết kế trong đó đối tượng trò chơi không cập nhật các thành phần của nó, mà là hệ thống con chịu trách nhiệm cho chính thành phần đó cập nhật tất cả chúng cùng một lúc. Điều này có thể đáng để đọc.


Câu trả lời này là tuyệt vời. Tôi vẫn chưa tìm ra cách để đoạn văn bản trong các bình luận (nhập khóa chỉ cần gửi) nhưng tôi sẽ giải quyết những phản hồi này. Mô tả của bạn về hệ thống Đối tượng / Thành phần có rất nhiều ý nghĩa. Vì vậy, chỉ cần làm rõ, trong trường hợp của PhysComponent, trong hàm tạo của thành phần, tôi có thể gọi hàm CreatRigidBody () của PhysManager's, sau đó lưu trữ một tham chiếu đến nó trong thành phần không?
Hiệp sĩ Aidan

Theo như phần "Nhận xét khác", cảm ơn vì điều này. Tôi đã trộn các chuỗi vì tôi thường thích sử dụng tất cả các hàm của Ogre làm cơ sở cho dự án của mình sử dụng Ogre, nhưng tôi đã bắt đầu chuyển đổi nó trong hệ thống Đối tượng / Thành phần vì nó thiếu bản đồ / cặp / v.v. Mặc dù vậy, bạn đã đúng và tôi đã chuyển đổi tất cả thành các thành viên tiêu chuẩn để tách nó khỏi Ogre.
Hiệp sĩ Aidan

1
+1 Đó là câu trả lời lành mạnh đầu tiên liên quan đến một mô hình dựa trên thành phần mà tôi đã đọc ở đây trong một thời gian, tương phản tốt với việc khái quát hóa quá mức
Maik Semder

5
Nó cho phép kết hợp tốt hơn (cả dữ liệu và trong bộ đệm hướng dẫn) và cho bạn khả năng giảm tải các bản cập nhật lên các luồng khác nhau hoặc xử lý công việc (ví dụ SPU). Trong một số trường hợp, các thành phần thậm chí sẽ không cần phải được cập nhật bằng bất cứ cách nào, điều đó có nghĩa là bạn có thể tránh được chi phí của cuộc gọi không đến phương thức update (). Cũng giúp bạn xây dựng các hệ thống hướng dữ liệu - tất cả là về xử lý hàng loạt, tận dụng các xu hướng hiện đại trong kiến ​​trúc CPU.

2
+1 cho "điều quan trọng nhất là hoàn thành công việc thay vì thống nhất thiết kế hoàn hảo"
Trasplazio Garzuglio

5

Kiến trúc thành phần là một giải pháp thay thế để tránh các hệ thống phân cấp lớn đạt được kế thừa tất cả các thành phần từ cùng một nút và các vấn đề về khớp nối dẫn.

Bạn đang hiển thị một kiến ​​trúc thành phần với các thành phần "chung". Bạn có logic cơ bản để đính kèm và tách các thành phần "chung". Một kiến ​​trúc với các thành phần chung khó đạt được hơn vì bạn không biết thành phần nào. Những lợi ích là phương pháp này có thể mở rộng.

Một kiến ​​trúc thành phần hợp lệ đạt được với các thành phần được xác định. Với ý nghĩa của tôi, giao diện được xác định, không phải là việc thực hiện. Ví dụ: GameObject có thể có IPhysicInstance, Transform, IMesh, IAnimationControll. Điều này có lợi ích là bạn biết giao diện và GameObject biết cách xử lý từng thành phần.

Đáp ứng với thuật ngữ khái quát quá mức

Tôi nghĩ rằng các khái niệm không rõ ràng. Khi tôi nói thành phần, không có nghĩa là tất cả thành phần của một đối tượng trò chơi phải kế thừa từ giao diện thành phần hoặc một cái gì đó tương tự. Tuy nhiên đây là cách tiếp cận cho các Thành phần chung, tôi nghĩ rằng đó là khái niệm mà bạn đặt tên là một thành phần.

Kiến trúc thành phần là một trong những kiến ​​trúc tồn tại cho mô hình đối tượng thời gian chạy. Nó không phải là duy nhất và không phải là tốt nhất cho mọi trường hợp, nhưng kinh nghiệm đã chứng minh rằng có rất nhiều lợi ích, như khớp nối thấp.

Tính năng chính phân biệt kiến ​​trúc thành phần là chuyển đổi quan hệ is-a thành has-a. Ví dụ, kiến ​​trúc đối tượng là-a:

là một kiến ​​trúc

Thay vì kiến ​​trúc đối tượng có-a (thành phần):

có kiến ​​trúc

Ngoài ra còn có kiến ​​trúc trung tâm tài sản:

Ví dụ, một kiến ​​trúc đối tượng bình thường là như thế này:

  • Đối tượng1

    • Vị trí = (0, 0, 0)
    • Định hướng = (0, 43, 0)
  • Đối tượng2

    • Vị trí = (10, 0, 0)
    • Định hướng = (0, 0, 30)

Một kiến ​​trúc tập trung vào tài sản:

  • Chức vụ

    • Đối tượng1 = (0, 0, 0)
    • Đối tượng2 = (10, 0, 0)
  • Sự định hướng

    • Đối tượng1 = (0, 43, 0)
    • Đối tượng2 = (0, 0, 30)

Nó là tốt hơn kiến ​​trúc mô hình đối tượng? Trong phối cảnh hiệu suất, nó tốt hơn thuộc tính trung tâm vì nó thân thiện với bộ đệm hơn.

Thành phần được tham chiếu đến quan hệ là-a thay vì has-a. Một thành phần có thể là ma trận Biến đổi, tứ phân vị, v.v. Nhưng mối quan hệ với đối tượng trò chơi là mối quan hệ là-a, đối tượng trò chơi không có sự biến đổi vì nó được kế thừa. Đối tượng trò chơi có (quan hệ có-a) sự biến đổi. Sự chuyển đổi sau đó là một thành phần.

Đối tượng trò chơi giống như một trung tâm. nếu bạn muốn một thành phần luôn ở đó, thì có lẽ thành phần đó (như ma trận) phải ở bên trong đối tượng chứ không phải là một con trỏ.

Không có một đối tượng trò chơi hoàn hảo cho tất cả các trường hợp, nó phụ thuộc vào công cụ, thư viện mà công cụ sử dụng. Có lẽ tôi muốn một chiếc máy ảnh không có lưới. Vấn đề với kiến ​​trúc is-a là nếu đối tượng trò chơi có lưới, thì máy ảnh kế thừa từ đối tượng trò chơi phải có lưới. Với các thành phần, máy ảnh có một bộ chuyển đổi, bộ điều khiển cho chuyển động và bất cứ thứ gì bạn cần.

Để biết thêm thông tin, chương "14.2. Kiến trúc mô hình đối tượng thời gian chạy" từ cuốn sách "Kiến trúc công cụ trò chơi" của "Jason Gregory" đề cập cụ thể đến chủ đề này.

Các sơ đồ UML được trích xuất từ ​​đó


Tôi không đồng ý với đoạn cuối, có xu hướng khái quát quá mức. Mô hình dựa trên thành phần không có nghĩa là mỗi chức năng phải là một thành phần, người ta vẫn phải xem xét mối quan hệ của chức năng và dữ liệu. Một AnimationContoder không có Lưới là vô dụng, vì vậy hãy đặt nó ở nơi nó thuộc về lưới. Đối tượng trò chơi không có biến đổi không phải là Đối tượng trò chơi, nó thuộc định nghĩa vào thế giới 3D, vì vậy hãy đặt nó như một thành viên bình thường vào Đối tượng trò chơi. Các quy tắc thông thường của chức năng đóng gói và dữ liệu vẫn được áp dụng.
Maik

@Maik Semder: Tôi đồng ý với bạn về việc khái quát hóa quá mức trong các điều khoản chung, nhưng tôi nghĩ rằng thành phần thuật ngữ này không rõ ràng. Tôi đã chỉnh sửa câu trả lời của mình. Đọc nó và cho tôi ấn tượng của bạn.
momboco

@momboco tốt, bạn ít lặp lại các điểm giống nhau hơn;) Transform và AnimationContoder vẫn được mô tả là các thành phần, theo quan điểm của tôi là sự lạm dụng mô hình thành phần. Điều quan trọng là xác định những gì nên được đưa vào một thành phần và những gì không:
Maik

Nếu cần một cái gì đó để làm cho Game-Object (GO) hoạt động ngay từ đầu, nói cách khác, nếu nó không phải là tùy chọn, nhưng bắt buộc, thì đó không phải là một thành phần. Các thành phần được cho là tùy chọn. Biến đổi là một ví dụ tốt, nó hoàn toàn không phải là tùy chọn cho GO, GO không có Transform không có ý nghĩa. Mặt khác, không phải mọi GO đều cần vật lý, vì vậy đó có thể là một thành phần.
Maik

Nếu có mối quan hệ chặt chẽ giữa 2 chức năng, như giữa AnimationContoder (AC) và Lưới, thì bằng mọi cách, đừng phá vỡ mối quan hệ này bằng cách nhấn AC vào một thành phần, ngược lại, Lưới là một thành phần hoàn hảo, nhưng thuộc về AC vào lưới.
Maik
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.