โดยทั่วไปส่วนประกอบของฟิสิกส์หรือกราฟิกนั้นสร้างขึ้นในระบบที่มุ่งเน้นส่วนประกอบได้อย่างไร


19

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

คลาส Object ของฉันมีลักษณะเช่นนี้จนถึงตอนนี้ (หากคุณสังเกตเห็นการเปลี่ยนแปลงใด ๆ ที่ฉันควรทำโปรดแจ้งให้เราทราบยังใหม่ต่อเรื่องนี้) ...

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

ตอนนี้ปัญหาที่ฉันพบคือประชากรทั่วไปจะใส่อะไรลงในส่วนประกอบเช่นฟิสิกส์ / กราฟิก สำหรับ Ogre (เครื่องมือเรนเดอร์ของฉัน) วัตถุที่มองเห็นจะประกอบด้วย Ogre :: SceneNode (อาจมีหลายตัว) ที่จะแนบกับฉาก Ogre :: Entity (อาจมีหลายตัว) เพื่อแสดงตาข่ายที่มองเห็นและอื่น ๆ เป็นการดีที่สุดหรือไม่ที่จะเพิ่ม GraphicComponent หลาย ๆ อันลงใน Object และปล่อยให้แต่ละ GraphicComponent จัดการหนึ่ง SceneNode / Entity หรือเป็นความคิดที่จะมีหนึ่งในแต่ละองค์ประกอบที่จำเป็น?

สำหรับวิชาฟิสิกส์ฉันรู้สึกสับสนมากขึ้น ฉันคิดว่าบางทีการสร้าง RigidBody และติดตามมวล / interia / ฯลฯ จะทำให้รู้สึก แต่ฉันกำลังมีปัญหาในการคิดวิธีการใส่ข้อมูลจำเพาะลงในคอมโพเนนต์อย่างแท้จริง

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

คำตอบ:


32

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

สิ่งนี้มีความได้เปรียบเพิ่มเติมในการรักษาระบบการเรนเดอร์และฟิสิกส์แยกจากระบบส่วนประกอบ

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

ในทำนองเดียวกันกับการเรนเดอร์ - renderer ของคุณจะมีบางอย่างที่แสดงข้อมูลอินสแตนซ์ที่จะเรนเดอร์และองค์ประกอบภาพของคุณจะทำการอ้างอิง

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

ความคิดเห็นอื่น ๆ

นี่ไม่เกี่ยวข้องกับคำถามโดยตรงของคุณ แต่นี่คือสิ่งที่ฉันสังเกตเห็นเมื่อดูรหัสของคุณ:

เหตุใดคุณจึงผสม Ogre :: String และ std :: string ในวัตถุเกมของคุณซึ่งเป็นวัตถุกราฟิกที่ไม่ใช่ภาพกราฟิกและดังนั้นจึงไม่ควรขึ้นกับ Ogre ฉันขอแนะนำให้ลบการอ้างอิงโดยตรงไปยัง Ogre ทั้งหมดยกเว้นในองค์ประกอบการแสดงผลเองซึ่งคุณควรทำการแปลงของคุณ

update () เป็น virtual virtual ซึ่งหมายความว่าต้อง subclass GameObject ซึ่งจริงๆแล้วเป็นประเภทตรงข้ามกับทิศทางที่คุณต้องการไปด้วยสถาปัตยกรรมส่วนประกอบ จุดหลักของการใช้ส่วนประกอบคือต้องการรวมการทำงานมากกว่าการสืบทอด

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

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


คำตอบนี้ยอดเยี่ยมมาก ฉันยังไม่ได้หาวิธีเว้นวรรควรรคในความคิดเห็น (ป้อนรหัสเพิ่งส่ง) แต่ฉันจะตอบคำถามเหล่านี้ คำอธิบายของคุณเกี่ยวกับระบบ Object / Component นั้นสมเหตุสมผลมาก ดังนั้นเพื่อชี้แจงในกรณีของ PhysicsComponent ใน Constructor ของส่วนประกอบฉันสามารถเรียกใช้ฟังก์ชั่น CreateRigidBody () ของ PhysicsManager ของฉันแล้วเก็บการอ้างอิงไปยังองค์ประกอบนั้นหรือไม่?
Aidan Knight

เท่าที่ส่วน "ความคิดเห็นอื่น" ขอขอบคุณสำหรับสิ่งนี้ ฉันผสมสตริงเพราะโดยทั่วไปแล้วฉันชอบใช้ฟังก์ชั่น Ogre ทั้งหมดเป็นพื้นฐานสำหรับโครงการที่ใช้ Ogre แต่ฉันเริ่มสลับมันในระบบ Object / Component เนื่องจากไม่มี map / pair / etc คุณคิดถูกและฉันได้เปลี่ยนพวกเขาไปเป็นสมาชิกมาตรฐานเพื่อแยกมันออกจาก Ogre
Aidan Knight

1
+1 นั่นเป็นคำตอบที่มีเหตุผลครั้งแรกเกี่ยวกับโมเดลที่อิงองค์ประกอบที่ฉันอ่านที่นี่ในขณะที่ความแตกต่างที่ดีกับการใช้งานเกินขนาดทั่วไป
Maik Semder

5
อนุญาตให้มีการเชื่อมโยงกันที่ดีขึ้น (ทั้งข้อมูลและในแคชคำสั่ง) และช่วยให้คุณมีความเป็นไปได้ในการถ่ายโอนการอัปเดตไปยังเธรดที่แตกต่างกันหรือกระบวนการของผู้ปฏิบัติงาน (SPU) ในบางกรณีองค์ประกอบจะไม่จำเป็นต้องได้รับการปรับปรุงอย่างใดซึ่งหมายความว่าคุณสามารถหลีกเลี่ยงค่าใช้จ่ายในการโทร no-op เพื่อ update () วิธีการ ยังช่วยให้คุณสร้างระบบที่มุ่งเน้นข้อมูล - มันคือทั้งหมดที่เกี่ยวกับการประมวลผลจำนวนมากซึ่งใช้ประโยชน์จากแนวโน้มที่ทันสมัยในสถาปัตยกรรมซีพียู

2
+1 สำหรับ "สิ่งที่สำคัญที่สุดคือการทำสิ่งต่าง ๆ ให้สำเร็จแทนที่จะต้องทนทุกข์ทรมานกับการออกแบบที่สมบูรณ์แบบ"
Trasplazio Garzuglio

5

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

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

สถาปัตยกรรมองค์ประกอบที่ถูกต้องสามารถทำได้ด้วยส่วนประกอบที่กำหนด ด้วยการกำหนดฉันหมายความว่าอินเทอร์เฟซถูกกำหนดไม่ใช่การใช้งาน ตัวอย่างเช่น GameObject สามารถมี IPhysicInstance, Transformation, IMesh, IAnimationController นี่เป็นข้อดีที่คุณรู้ว่าอินเทอร์เฟซและ GameObject รู้วิธีจัดการกับแต่ละองค์ประกอบ

การตอบสนองต่อคำว่า

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

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

คุณสมบัติหลักที่แยกความแตกต่างขององค์ประกอบสถาปัตยกรรมคือการแปลงความสัมพันธ์ is-a ไปเป็น has-a ตัวอย่างเช่นสถาปัตยกรรมวัตถุคือ:

เป็นสถาปัตยกรรม

แทนที่จะเป็นสถาปัตยกรรมวัตถุมี - (ส่วนประกอบ):

มีสถาปัตยกรรม

นอกจากนี้ยังมีสถาปัตยกรรมเป็นศูนย์กลางคุณสมบัติ:

ตัวอย่างเช่นสถาปัตยกรรมวัตถุปกติเป็นดังนี้:

  • Object1

    • ตำแหน่ง = (0, 0, 0)
    • การวางแนว = (0, 43, 0)
  • Object2

    • ตำแหน่ง = (10, 0, 0)
    • การวางแนว = (0, 0, 30)

สถาปัตยกรรมที่เน้นคุณสมบัติ:

  • ตำแหน่ง

    • Object1 = (0, 0, 0)
    • Object2 = (10, 0, 0)
  • ปฐมนิเทศ

    • Object1 = (0, 43, 0)
    • Object2 = (0, 0, 30)

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

คอมโพเนนต์ถูกอ้างถึงความสัมพันธ์ is-a แทนที่จะเป็น has-a ส่วนประกอบสามารถเป็นเมทริกซ์การแปลง, quaternion, ฯลฯ แต่ความสัมพันธ์กับเกมวัตถุคือความสัมพันธ์คือ -, เกม - วัตถุไม่มีการเปลี่ยนแปลงเพราะมันเป็นกรรมพันธุ์ เกมวัตถุมี (ความสัมพันธ์มี -a) การเปลี่ยนแปลง การเปลี่ยนแปลงนั้นเป็นองค์ประกอบ

วัตถุในเกมเป็นเหมือนฮับ หากคุณต้องการส่วนประกอบที่มักจะมีอยู่แล้วบางทีส่วนประกอบ (เช่นเมทริกซ์) ควรอยู่ภายในวัตถุและไม่ใช่ตัวชี้

ไม่มีเกมวัตถุที่สมบูรณ์แบบสำหรับทุกกรณีขึ้นอยู่กับเอ็นจิ้นห้องสมุดที่เอ็นจิ้นใช้ บางทีฉันต้องการกล้องที่ไม่มีตาข่าย ปัญหาของสถาปัตยกรรมแบบ is-a คือถ้าเกมวัตถุมีตาข่ายแล้วกล้องที่สืบทอดจากเกมวัตถุจะต้องมีตาข่าย ด้วย componenets กล้องมีการแปลงตัวควบคุมสำหรับการเคลื่อนไหวและทุกสิ่งที่คุณต้องการ

สำหรับข้อมูลเพิ่มเติมบทที่ "14.2 สถาปัตยกรรมแบบจำลองวัตถุ Runtime" จากหนังสือ "Game Engine Architecture" ของ "Jason Gregory" เกี่ยวข้องกับหัวข้อนี้โดยเฉพาะ

ไดอะแกรม UML ถูกแยกออกมาจากที่นั่น


ฉันไม่เห็นด้วยกับย่อหน้าที่ผ่านมามีแนวโน้มของการพูดเกินจริงมากเกินไป แบบจำลองที่อิงองค์ประกอบไม่ได้หมายความว่าฟังก์ชันการทำงานแต่ละอย่างและทุกอย่างจะต้องเป็นองค์ประกอบ แต่ก็ยังต้องพิจารณาถึงความสัมพันธ์ของฟังก์ชันและข้อมูล AnimationController แบบไม่มีตาข่ายไม่มีประโยชน์ดังนั้นให้วางไว้ในตำแหน่งที่เป็นตาข่าย Game-Object ที่ไม่มีการแปลงไม่ได้เป็น Game-Object มันเป็นของคำจำกัดความในโลก 3 มิติดังนั้นให้มันเป็นสมาชิกปกติใน Game-Object ยังคงใช้กฎปกติของฟังก์ชันการห่อหุ้มและข้อมูล
Maik Semder

@Maik Semder: ฉันเห็นด้วยกับคุณในการพูดเกินจริงในแง่ทั่วไป แต่ฉันคิดว่าองค์ประกอบคำไม่ชัดเจน ฉันแก้ไขคำตอบของฉันแล้ว อ่านและให้ความประทับใจแก่คุณ
momboco

@omboco ดีคุณทำซ้ำจุดเดียวกันน้อยกว่า); Transform และ AnimationController ยังคงอธิบายว่าเป็นองค์ประกอบซึ่งในมุมมองของฉันคือการใช้มากเกินไปของรูปแบบองค์ประกอบ กุญแจสำคัญคือการกำหนดสิ่งที่ควรใส่ลงในองค์ประกอบและสิ่งที่ไม่:
Maik Semder

หากจำเป็นต้องมีบางสิ่งบางอย่างเพื่อทำให้ Game-Object (GO) ทำงานได้ตั้งแต่แรกกล่าวอีกนัยหนึ่งถ้าไม่ใช่ตัวเลือก แต่จำเป็นต้องมีสิ่งนั้นไม่ใช่ส่วนประกอบ ส่วนประกอบควรจะเป็นตัวเลือก การแปลงเป็นตัวอย่างที่ดีไม่ใช่ตัวเลือกเลยสำหรับ GO, GO ที่ไม่มีการแปลงทำให้ไม่มีเหตุผล ในทางตรงกันข้ามไม่ใช่ทุก ๆ GO ที่ต้องการฟิสิกส์เพื่อที่จะได้เป็นองค์ประกอบ
Maik Semder

หากมีความสัมพันธ์ที่แน่นแฟ้นระหว่าง 2 funtionalities ระหว่าง AnimationController (AC) และ Mesh ดังนั้นไม่ว่าด้วยวิธีใดก็ตามจะไม่ทำลายความสัมพันธ์นี้โดยการกด AC เป็นส่วนประกอบในทางตรงกันข้าม Mesh เป็นส่วนประกอบที่สมบูรณ์แบบ แต่ AC นั้น เข้าไปในตาข่าย
Maik Semder
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.