Hệ thống thực thể thành phần - Cập nhật và gọi đơn đặt hàng


10

Để có được các thành phần để có thể cập nhật mọi khung hình (và loại bỏ chức năng này khỏi các thành phần không cần thiết), tôi đã có ý tưởng tạo ra một thành phần UpdateComponent. Các thành phần khác như MovableComponent(giữ vận tốc) sẽ kế thừa từ IUpdatablelớp trừu tượng. Điều này buộc MovableComponentphải thực hiện một Update(gametime dt)phương thức và một phương thức khác RegisterWithUpdater()đưa ra UpdateComponentmột con trỏ tới MovableComponent. Nhiều thành phần có thể làm điều này và sau đó UpdateComponentcó thể gọi tất cả các Update(gametime dt)phương thức của chúng mà không cần phải quan tâm đến chúng hoặc chúng là gì.

Câu hỏi của tôi là:

  1. Điều này có vẻ như bất cứ điều gì là bình thường hoặc được sử dụng bởi bất cứ ai? Tôi không thể tìm thấy bất cứ điều gì về chủ đề này.
  2. Làm thế nào tôi có thể duy trì một trật tự cho các thành phần như vật lý sau đó thay đổi vị trí? Điều này thậm chí còn cần thiết?
  3. Các cách khác để đảm bảo rằng các thành phần nên xử lý mọi khung hình trên thực tế được xử lý là gì?

EDIT
Tôi nghĩ rằng tôi sẽ xem xét làm thế nào để cung cấp cho người quản lý thực thể một danh sách các loại có thể cập nhật. Sau đó TẤT CẢ các thành phần của loại đó có thể cập nhật thay vì quản lý nó trên mỗi thực thể (dù sao chỉ là các chỉ mục trong hệ thống của tôi).

Vẫn. Câu hỏi của tôi vẫn còn hiệu lực với tôi. Tôi không biết điều này có hợp lý / bình thường không, hay những gì người khác có xu hướng làm.

Ngoài ra, những người ở Insomniac thật tuyệt vời! /BIÊN TẬP

Mã sôi cho ví dụ trước:

class IUpdatable
{
public:
    virtual void Update(float dt) = 0;
protected:
    virtual void RegisterAsUpdatable() = 0;
};

class Component
{
    ...
};

class MovableComponent: public Component, public IUpdatable
{
public:
    ...
    virtual void Update(float dt);
private:
    ...
    virtual void RegisterWithUpdater();
};

class UpdateComponent: public Component
{
public:
    ...
    void UpdateAll();
    void RegisterUpdatable(Component* component);
    void RemoveUpdatable(Component* component);
private:
    ...
    std::set<Component*> updatables_;
};

Bạn có một ví dụ cho một thành phần không thể cập nhật? Điều đó có vẻ khá vô dụng. Đặt chức năng cập nhật là một chức năng ảo vào thành phần. Sau đó, chỉ cần cập nhật tất cả các thành phần trong thực thể, không cần "UpdateComponent"
Maik Semder

Một số thành phần giống như chủ sở hữu dữ liệu. Giống như PositionComponent. Nhiều đối tượng có thể có một vị trí, nhưng nếu chúng đứng yên, có thể chiếm đa số, tất cả các cuộc gọi ảo bổ sung đó có thể tích tụ. Hoặc nói một HealthComponent. Điều đó không cần làm bất cứ điều gì ở mọi khung hình, chỉ cần sửa đổi khi cần. Có thể chi phí không quá tệ nhưng UpdateComponent của tôi là một nỗ lực để không có Update () trong thành phần MERYI.
ptpaterson

5
Một thành phần chỉ chứa dữ liệu và không có chức năng để thay đổi nó theo thời gian là theo định nghĩa không phải là một thành phần. Phải có một số chức năng trong thành phần thay đổi theo thời gian, do đó cần một chức năng cập nhật. Nếu thành phần của bạn không cần chức năng cập nhật, thì bạn biết nó không phải là thành phần và bạn nên suy nghĩ lại về thiết kế. Một chức năng cập nhật trong thành phần sức khỏe có ý nghĩa, ví dụ bạn muốn NPC của mình được chữa lành khỏi thiệt hại trong một thời gian.
Maik

@Maik Quan điểm của tôi KHÔNG phải là các thành phần sẽ không bao giờ / không bao giờ có thể thay đổi. Tôi đồng ý rằng điều đó thật ngớ ngẩn. Họ chỉ không cần cập nhật mọi khung hình, thay vào đó sẽ được thông báo để thay đổi thông tin của họ khi cần thiết. Trong trường hợp sức khỏe theo thời gian, sẽ có một thành phần thưởng sức khỏe mà DOES có bản cập nhật. Tôi không nghĩ có bất kỳ lý do nào để kết hợp cả hai.
ptpaterson

Tôi cũng muốn lưu ý rằng mã tôi đã đăng chỉ có những gì cần thiết để giải thích khái niệm UpdateComponent. Nó loại trừ tất cả các hình thức giao tiếp khác giữa các thành phần.
ptpaterson

Câu trả lời:


16

Một trong những lợi ích chính của hệ thống thành phần là khả năng tận dụng các mẫu bộ đệm - icache tốt và dự đoán vì bạn chạy mã giống nhau nhiều lần, dcache tốt vì bạn có thể phân bổ các đối tượng trong nhóm đồng nhất và vì vtables, nếu bất kỳ, giữ nóng.

Cách bạn cấu trúc các thành phần của mình, lợi thế này biến mất hoàn toàn và trên thực tế có thể trở thành trách nhiệm thực hiện so với hệ thống dựa trên thừa kế, khi bạn thực hiện nhiều cuộc gọi ảo hơn và nhiều đối tượng hơn với vtables.

Những gì bạn nên làm là lưu trữ nhóm theo từng loại và lặp lại từng loại một cách độc lập để thực hiện cập nhật.

Điều này có vẻ như bất cứ điều gì là bình thường hoặc được sử dụng bởi bất cứ ai? Tôi không thể tìm thấy bất cứ điều gì về chủ đề này.

Nó không phổ biến trong các trò chơi lớn vì nó không có lợi thế. Nó phổ biến trong nhiều trò chơi, nhưng nó không thú vị về mặt kỹ thuật, vì vậy không ai viết về nó.

Làm thế nào tôi có thể duy trì một trật tự cho các thành phần như vật lý sau đó thay đổi vị trí? Điều này thậm chí còn cần thiết?

Mã trong các ngôn ngữ như C ++ có cách tự nhiên để thực hiện lệnh: nhập các câu lệnh theo thứ tự đó.

for (PhysicsComponent *c : physics_components)
    c->update(dt);
for (PositionComponent *c : position_components)
    c->update(dt);

Trong thực tế, điều đó không có ý nghĩa vì không có hệ thống vật lý mạnh mẽ nào được cấu trúc theo cách đó - bạn không thể cập nhật một đối tượng vật lý duy nhất. Thay vào đó, mã sẽ trông giống như:

physics_step();
for (PositionComponent *c : position_components)
    c->update(dt);
// Updates the position data from the physics data.

Cảm ơn. Tôi đã bắt đầu toàn bộ dự án này với ý định hướng dữ liệu (không giống như dữ liệu được điều khiển), ngăn chặn các lỗi nhớ cache và như vậy. Nhưng một khi tôi bắt đầu viết mã, tôi quyết định chỉ làm một cái gì đó hoạt động tốt. Hóa ra nó làm mọi thứ khó khăn hơn với tôi. Và đối với nghiêm trọng, bài báo mất ngủ đó là tuyệt vời!
ptpaterson

@Joe +1 cho câu trả lời rất hay. Mặc dù tôi muốn biết icache và dcache là gì. Cảm ơn
Ray Dey

Bộ nhớ cache hướng dẫn và bộ đệm dữ liệu. Bất kỳ văn bản giới thiệu về kiến ​​trúc máy tính nên bao gồm chúng.

@ptpaterson: Lưu ý rằng có một lỗi nhỏ trong bản trình bày Insomniac - lớp thành phần phải chứa chỉ số bảng liệt kê của nó hoặc bạn cần một ánh xạ riêng của các chỉ số nhóm để phân loại các chỉ mục.

3

Những gì bạn đang nói là hợp lý và khá phổ biến, tôi nghĩ vậy. Điều này có thể cung cấp cho bạn một số thông tin thêm.


Tôi nghĩ rằng tôi đã xem qua bài báo đó một vài tuần trước. Tôi đã có thể mã hóa một vài phiên bản rất đơn giản của một hệ thống thực thể dựa trên thành phần, mỗi phiên bản rất khác nhau khi tôi thử những thứ khác nhau. Cố gắng tập hợp tất cả các bài viết và ví dụ vào một cái gì đó tôi muốn và có thể làm được. cảm ơn!
ptpaterson

0

Tôi thích những cách tiếp cận này:

Ngắn gọn: Tránh giữ hành vi cập nhật trong các thành phần. Các thành phần không phải là hành vi. Hành vi (bao gồm các bản cập nhật) có thể được thực hiện trong một số hệ thống con đơn lẻ. Cách tiếp cận đó cũng có thể giúp xử lý hàng loạt các hành vi tương tự cho nhiều thành phần (có thể sử dụng các hướng dẫn song song hoặc SIMD trên dữ liệu thành phần).

Phương pháp IUpditable và phương pháp Cập nhật (gametime dt) có vẻ hơi quá hạn chế và giới thiệu các khoản giảm giá bổ sung. Có thể sẽ ổn nếu bạn không sử dụng phương pháp tiếp cận hệ thống con, nhưng nếu bạn sử dụng chúng, thì IUpditable là một mức phân cấp dự phòng. Rốt cuộc, MoveSystem nên biết rằng nó phải cập nhật trực tiếp các thành phần Vị trí và / hoặc Vận tốc cho tất cả các thực thể có các thành phần này, do đó không cần một số thành phần IUpditable trung gian.

Nhưng bạn có thể sử dụng thành phần Cập nhật như một cơ chế để bỏ qua việc cập nhật một số thực thể mặc dù chúng có các thành phần Vị trí và / hoặc Vận tốc. Thành phần có thể cập nhật có thể có cờ bool có thể được đặt thành falsevà nó sẽ báo hiệu cho mọi hệ thống con nhận biết cập nhật rằng thực thể cụ thể này hiện không nên được cập nhật (mặc dù trong bối cảnh như vậy, Freezable dường như là tên thích hợp hơn cho thành phần).

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.