ระบบเอนทิตีส่วนประกอบ - อัปเดตและคำสั่งโทร


10

เพื่อให้ส่วนประกอบสามารถอัปเดตทุกเฟรม (และปล่อยให้ฟังก์ชันนี้ออกจากส่วนประกอบที่ไม่จำเป็นต้องใช้) ฉันมีแนวคิดที่จะสร้างคอมโพเนนต์ UpdateComponent ส่วนประกอบอื่น ๆ เช่นMovableComponent(ซึ่งมีความเร็ว) จะสืบทอดมาจากIUpdatableคลาสนามธรรม กองกำลังนี้MovableComponentจะใช้Update(gametime dt)วิธีการและอื่น ๆRegisterWithUpdater()ที่จะช่วยให้ชี้ไปUpdateComponent MovableComponentส่วนประกอบจำนวนมากสามารถทำสิ่งนี้ได้และUpdateComponentสามารถเรียกใช้Update(gametime dt)วิธีการทั้งหมดได้โดยไม่ต้องสนใจว่าเขาเป็นใครหรืออะไร

คำถามของฉันคือ:

  1. สิ่งนี้ดูเหมือนจะเป็นสิ่งที่ปกติหรือเคยถูกใช้โดยทุกคนหรือไม่ ฉันไม่พบสิ่งใดในหัวข้อ
  2. ฉันจะรักษาคำสั่งซื้อส่วนประกอบเช่นฟิสิกส์แล้วเปลี่ยนตำแหน่งได้อย่างไร มันจำเป็นหรือไม่
  3. มีวิธีอื่นใดในการประกันว่าส่วนประกอบที่ควรประมวลผลทุกเฟรมกำลังดำเนินการในความเป็นจริง

แก้ไข
ฉันคิดว่าฉันจะให้ความสำคัญกับรายการประเภทที่สามารถอัปเดตได้ จากนั้นองค์ประกอบทั้งหมดของประเภทนั้นสามารถอัปเดตได้มากกว่าการจัดการมันต่อเอนทิตี (ซึ่งเป็นเพียงดัชนีในระบบของฉัน)

ยังคง คำถามของฉันยังคงใช้ได้สำหรับฉัน ฉันไม่รู้ว่านี่เป็นเหตุผล / ปกติหรือสิ่งที่คนอื่นมักจะทำ

นอกจากนี้ผู้คนที่อินซอมเนียก็ยอดเยี่ยมมาก! / แก้ไข

ตัวอย่างโค้ดก่อนหน้านี้:

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_;
};

คุณมีตัวอย่างสำหรับองค์ประกอบที่ไม่สามารถอัปเดตได้หรือไม่? ดูเหมือนจะไร้ประโยชน์ ใส่ฟังก์ชั่นอัพเดทเป็นฟังก์ชั่นเสมือนลงในองค์ประกอบ จากนั้นเพียงอัปเดตส่วนประกอบทั้งหมดในเอนทิตีไม่จำเป็นต้องใช้ "UpdateComponent"
Maik Semder

ส่วนประกอบบางอย่างนั้นเหมือนตัวเก็บข้อมูล เช่นเดียวกับ PositionComponent วัตถุจำนวนมากสามารถมีตำแหน่ง แต่ถ้าพวกเขาอยู่กับที่ซึ่งอาจเป็นเสียงส่วนใหญ่การโทรเสมือนเหล่านั้นทั้งหมดสามารถสร้างขึ้นได้ หรือพูดว่า HealthComponent ไม่จำเป็นต้องทำอะไรทุกเฟรมเพียงแค่ทำการปรับเปลี่ยนเมื่อจำเป็น บางทีค่าโสหุ้ยนั้นไม่ดี แต่ UpdateComponent ของฉันเป็นความพยายามที่จะไม่มี Update () ในทุกองค์ประกอบ
ptpaterson

5
องค์ประกอบที่เก็บข้อมูลเท่านั้นและไม่มีฟังก์ชั่นที่จะเปลี่ยนแปลงเมื่อเวลาผ่านไปโดยคำจำกัดความไม่ใช่องค์ประกอบ จะต้องมีฟังก์ชั่นบางอย่างในองค์ประกอบที่เปลี่ยนแปลงตลอดเวลาจึงต้องการฟังก์ชั่นการอัพเดท หากองค์ประกอบของคุณไม่ต้องการฟังก์ชั่นการอัพเดทคุณจะรู้ว่าไม่ใช่องค์ประกอบและคุณควรพิจารณาการออกแบบใหม่ ฟังก์ชั่นอัพเดทในองค์ประกอบด้านสุขภาพนั้นสมเหตุสมผลเช่นคุณต้องการให้ NPC ของคุณรักษาความเสียหายในบางครั้ง
Maik Semder

@Maik จุดของฉันไม่ใช่ว่าเป็นส่วนประกอบที่จะไม่มีวันเปลี่ยนแปลง / ไม่สามารถเปลี่ยนแปลงได้ ฉันเห็นด้วยที่โง่ พวกเขาไม่จำเป็นต้องอัพเดททุกเฟรมแทนที่จะได้รับแจ้งให้เปลี่ยนข้อมูลเมื่อจำเป็น ในกรณีของสุขภาพเมื่อเวลาผ่านไปจะมีองค์ประกอบโบนัสสุขภาพที่ไม่มีการปรับปรุง ฉันไม่คิดว่าจะมีเหตุผลใดที่จะรวมสองสิ่งนี้เข้าด้วยกัน
ptpaterson

ฉันต้องการทราบด้วยว่ารหัสที่ฉันโพสต์มีเพียงสิ่งที่จำเป็นในการอธิบายแนวคิด UpdateComponent มันไม่รวมรูปแบบการสื่อสารอื่น ๆ ทั้งหมดระหว่างส่วนประกอบ
ptpaterson

คำตอบ:


16

หนึ่งในประโยชน์หลักของระบบส่วนประกอบคือความสามารถในการใช้ประโยชน์จากรูปแบบแคช - icache ที่ดีและการทำนายเพราะคุณเรียกใช้รหัสเดียวกันซ้ำแล้วซ้ำอีกดี dcache ที่ดีเพราะคุณสามารถจัดสรรวัตถุในกลุ่มที่เป็นเนื้อเดียวกันและเพราะ vtables ถ้า ใด ๆ อยู่ร้อน

วิธีที่คุณได้จัดโครงสร้างส่วนประกอบของคุณข้อดีนี้จะหายไปอย่างสมบูรณ์และในความเป็นจริงอาจกลายเป็นภาระด้านประสิทธิภาพเมื่อเทียบกับระบบที่ใช้การสืบทอดในขณะที่คุณทำการโทรเสมือนและวัตถุที่มี vtables มากขึ้น

สิ่งที่คุณควรทำคือการเก็บพูลตามประเภทและวนซ้ำแต่ละประเภทเพื่อทำการอัพเดต

สิ่งนี้ดูเหมือนจะเป็นสิ่งที่ปกติหรือเคยถูกใช้โดยทุกคนหรือไม่ ฉันไม่พบสิ่งใดในหัวข้อ

มันไม่ธรรมดาในเกมใหญ่เพราะมันไม่ได้เปรียบ เป็นเรื่องธรรมดาในเกมมากมาย แต่ก็ไม่น่าสนใจทางเทคนิคดังนั้นจึงไม่มีใครเขียนถึงมัน

ฉันจะรักษาคำสั่งซื้อส่วนประกอบเช่นฟิสิกส์แล้วเปลี่ยนตำแหน่งได้อย่างไร มันจำเป็นหรือไม่

โค้ดในภาษาอย่าง C ++ มีวิธีการสั่งซื้อที่เป็นธรรมชาติ: พิมพ์คำสั่งในลำดับนั้น

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

ในความเป็นจริงมันไม่สมเหตุสมผลเพราะไม่มีระบบฟิสิกส์ที่แข็งแกร่งมีโครงสร้างแบบนั้น - คุณไม่สามารถอัปเดตวัตถุฟิสิกส์เดียวได้ รหัสจะมีลักษณะเหมือน:

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

ขอบคุณ ฉันเริ่มโครงการทั้งหมดนี้โดยคำนึงถึงข้อมูล (ไม่เหมือนกับการขับเคลื่อนข้อมูล) ในใจเพื่อป้องกันการพลาดแคชและสิ่งอื่น ๆ แต่เมื่อฉันเริ่มเขียนโค้ดฉันตัดสินใจที่จะทำสิ่งที่ได้ผลกับดอทคอม ปรากฎว่ามันทำให้สิ่งต่าง ๆ ยากขึ้นสำหรับฉัน และสำหรับบทความที่มีอาการนอนไม่หลับนั้นร้ายแรงมาก!
ptpaterson

@Joe +1 สำหรับคำตอบที่ดีมาก แม้ว่าฉันต้องการทราบว่า icache และ dcache คืออะไร ขอบคุณ
Ray Dey

แคชคำสั่งและแคชข้อมูล ข้อความเกริ่นนำใด ๆ เกี่ยวกับสถาปัตยกรรมคอมพิวเตอร์ควรครอบคลุมเนื้อหาเหล่านั้น

@ptpaterson: โปรดทราบว่ามีความผิดพลาดเล็กน้อยในงานนำเสนอ Insomniac คลาสองค์ประกอบต้องมีดัชนีบัญชีรายชื่อหรือคุณจำเป็นต้องมีการแมปดัชนีดัชนีสระว่ายน้ำแยกต่างหากกับดัชนีบัญชีรายชื่อ

3

สิ่งที่คุณกำลังพูดถึงมีเหตุผลและเป็นเรื่องปกติฉันคิดว่า สิ่งนี้อาจให้ข้อมูลเพิ่มเติมแก่คุณ


ฉันคิดว่าฉันเจอบทความนั้นเมื่อสองสามสัปดาห์ก่อน ฉันสามารถเขียนโค้ดแบบง่าย ๆ ของระบบเอนทิตีที่ใช้องค์ประกอบหลาย ๆ แบบซึ่งแตกต่างกันมากเมื่อฉันลองทำสิ่งต่าง ๆ พยายามนำบทความและตัวอย่างทั้งหมดมารวมกันเป็นสิ่งที่ฉันต้องการและสามารถทำได้ ขอบคุณ!
ptpaterson

0

ฉันชอบวิธีการเหล่านี้:

ไม่นาน: หลีกเลี่ยงพฤติกรรมการอัพเดทภายในส่วนประกอบ ส่วนประกอบไม่ใช่พฤติกรรม พฤติกรรม (รวมถึงการปรับปรุง) สามารถนำมาใช้ในระบบย่อยอินสแตนซ์เดียวบางอย่าง วิธีการดังกล่าวอาจช่วยในการประมวลผลพฤติกรรมที่คล้ายกันสำหรับหลาย ๆ องค์ประกอบ (อาจใช้คำสั่งแบบขนานหรือคำสั่ง SIMD สำหรับข้อมูลส่วนประกอบ)

แนวคิดของ IUpdatable และการอัปเดต (gametime dt) ดูเหมือนจะเข้มงวดเกินไปและแนะนำการพึ่งพาเพิ่มเติม มันอาจจะดีถ้าคุณไม่ได้ใช้วิธีการระบบย่อย แต่ถ้าคุณใช้พวกมัน IUpdatable จะเป็นลำดับชั้นที่ซ้ำซ้อน ท้ายที่สุด MovingSystem ควรรู้ว่ามันจะต้องอัพเดทองค์ประกอบ Location และ / หรือ Velocity โดยตรงสำหรับเอนทิตีทั้งหมดที่มีส่วนประกอบเหล่านี้ดังนั้นจึงไม่จำเป็นต้องมีองค์ประกอบ IUpdatable ระดับกลางบางตัว

แต่คุณสามารถใช้ส่วนประกอบที่อัปเดตได้เป็นกลไกในการข้ามการอัปเดตบางเอนทิตีแม้จะมีส่วนประกอบตำแหน่งและ / หรือความเร็ว องค์ประกอบที่สามารถอัปเดตได้อาจมีค่าสถานะบูลซึ่งสามารถตั้งค่าได้falseและที่จะส่งสัญญาณทุกระบบย่อย updatable-aware ที่ปัจจุบันนี้ไม่ควรปรับปรุงเอนทิตีเฉพาะ (ในบริบทเช่นนี้ Freezable ดูเหมือนจะเป็นชื่อที่เหมาะสมกว่าสำหรับองค์ประกอบ)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.