मुझे ऑब्जेक्ट्स को रेंडरिंग से अलग क्यों करना चाहिए?


11

अस्वीकरण: मुझे पता है कि एक इकाई प्रणाली पैटर्न क्या है और मैं इसका उपयोग नहीं कर रहा हूं ।

मैंने ऑब्जेक्ट को अलग करने और रेंडर करने के बारे में बहुत कुछ पढ़ा है। इस तथ्य के बारे में कि खेल तर्क अंतर्निहित रेंडरिंग इंजन से स्वतंत्र होना चाहिए। यह सब ठीक है और बांका है और यह सही समझ में आता है, लेकिन यह बहुत सारे अन्य दर्द का कारण बनता है:

  • लॉजिक ऑब्जेक्ट और रेंडरिंग ऑब्जेक्ट के बीच सिंक्रोनाइज़ेशन की आवश्यकता (वह जो एनिमेशन की स्थिति, स्प्राइट आदि को बनाए रखता है)
  • तर्क वस्तु की वास्तविक स्थिति को पढ़ने के लिए रेंडरिंग ऑब्जेक्ट के लिए लॉजिक ऑब्जेक्ट को जनता के लिए खोलने की आवश्यकता है (अक्सर तर्क ऑब्जेक्ट को आसानी से गूंगा गटर और सेटर ऑब्जेक्ट में बदलने के लिए अग्रणी)

यह मेरे लिए एक अच्छे समाधान की तरह नहीं है। दूसरी ओर किसी वस्तु की उसके 3 डी (या 2 डी) प्रतिनिधित्व के रूप में कल्पना करना बहुत सहज है और इसे बनाए रखना बहुत आसान है (और संभवतः बहुत अधिक संक्षिप्त रूप में भी)।

क्या ग्राफिक प्रतिनिधित्व और गेम लॉजिक को एक साथ बनाए रखने का एक तरीका है (सिंक्रनाइज़ेशन मुद्दों से बचना) लेकिन रेंडरिंग इंजन को दूर रखा जाए? या खेल तर्क और प्रतिपादन को अलग करने का एक तरीका है जो उपरोक्त कमियों का कारण नहीं है?

(संभवतः उदाहरणों के साथ, मैं अमूर्त वार्ता को समझने में बहुत अच्छा नहीं हूँ)


1
यदि आप कहते हैं कि जब आप कहते हैं कि आप इकाई प्रणाली पैटर्न का उपयोग नहीं कर रहे हैं, तो इसका एक उदाहरण प्रदान करना उपयोगी होगा, और आप कैसे सोचते हैं कि आपको इकाई की चिंता से प्रतिपादन की चिंता को अलग करना चाहिए या नहीं। खेल तर्क।
michael.bartnett

@ michael.bartnett, मैं छोटे पुन: प्रयोज्य घटकों में वस्तुओं को अलग नहीं कर रहा हूं जो सिस्टम द्वारा संभाले जाते हैं, जिस तरह से पैटर्न का अधिकांश कार्यान्वयन होता है। मेरा कोड इसके बजाय MVC पैटर्न के लिए अधिक प्रयास है। लेकिन यह वास्तव में मायने नहीं रखता क्योंकि प्रश्न किसी भी कोड (एक भाषा भी नहीं) पर निर्भर नहीं है। मैंने डिस्क्लेमर डाला है क्योंकि मुझे पता था कि कुछ लोगों ने मुझे ईसीएस का उपयोग करने के लिए समझाने की कोशिश की होगी, जो कैंसर को ठीक करता है। और, जैसा कि आप देख सकते हैं, यह वैसे भी हुआ।
जूता

जवाबों:


13

मान लीजिए कि आपके पास एक दृश्य है जो एक दुनिया , एक खिलाड़ी और एक बॉस से बना है। ओह, और यह एक तीसरा व्यक्ति खेल है, इसलिए आपके पास एक कैमरा भी है ।

तो आपका दृश्य कुछ इस प्रकार है:

class Scene {
    World* world
    Player* player
    Enemy* boss
    Camera* camera
}

(कम से कम, यह मूल डेटा है । आपके पास डेटा कैसे है, आप पर निर्भर है।)

जब आप गेम खेल रहे हों, तब ही आप अपडेट और रेंडर करना चाहते हैं, जब विराम न हो या मुख्य मेनू में हो ... तो आप इसे गेम स्टेट से अटैच कर दें!

State* gameState = new State();
gameState->addScene(scene);

अब आपके गेम स्टेट में एक दृश्य है। अगला, आप दृश्य पर तर्क चलाना चाहते हैं, और दृश्य प्रस्तुत करना चाहते हैं। तर्क के लिए, आप बस एक अद्यतन फ़ंक्शन चलाते हैं।

State::update(double delta) {
    scene->update(delta);
}

इस तरह आप Sceneकक्षा में सभी खेल तर्क रख सकते हैं । और सिर्फ संदर्भ के लिए, एक इकाई घटक प्रणाली इसके बजाय ऐसा कर सकती है:

State::update(double delta) {
    physicsSystem->applyPhysics(scene);
}

वैसे भी, अब आप अपने दृश्य को अपडेट करने में कामयाब हो गए हैं। अब आप इसे प्रदर्शित करना चाहते हैं! जिसके लिए हम उपरोक्त के समान कुछ करते हैं:

State::render() {
    renderSystem->render(scene);
}

तुम वहाँ जाओ। रेंडरसिस्टम दृश्य से जानकारी पढ़ता है, और उपयुक्त छवि प्रदर्शित करता है। सरलीकृत, दृश्य को प्रस्तुत करने की विधि इस तरह दिख सकती है:

RenderSystem::renderScene(Scene* scene) {
    Camera* camera = scene->camera;
    lookAt(camera); // Set up the appropriate viewing matrices based on 
                    // the camera location and direction

    renderHeightmap(scene->getWorld()->getHeightMap()); // Just as an example, you might
                                                        // use a height map as your world
                                                        // representation.
    renderModel(scene->getPlayer()->getType()); // getType() will return, for example "orc"
                                                // or "human"

    renderModel(scene->getBoss()->getType());
}

वास्तव में सरलीकृत, आपको अभी भी आवश्यकता होगी, उदाहरण के लिए, आपके खिलाड़ी कहां है और वह कहां देख रहा है, इसके आधार पर एक रोटेशन और अनुवाद लागू करें। (मेरा उदाहरण एक 3 डी गेम है, यदि आप 2 डी के साथ जाते हैं, तो यह पार्क में टहलने जाएगा)।

मुझे आशा है कि यह वही है जो आप ढूंढ रहे थे? जैसा कि आप ऊपर से याद कर सकते हैं, रेंडर सिस्टम गेम के तर्क की परवाह नहीं करता है । यह केवल दृश्य की वर्तमान स्थिति को रेंडर करने के लिए उपयोग करता है, अर्थात यह रेंडर करने के लिए इससे आवश्यक जानकारी खींचता है। और खेल तर्क? यह परवाह नहीं करता है कि रेंडरर क्या करता है। बिल्ली, यह परवाह नहीं करता है अगर यह बिल्कुल भी प्रदर्शित होता है!

और आपको दृश्य को जानकारी प्रदान करने की आवश्यकता नहीं है। यह पर्याप्त होना चाहिए कि रेंडरर जानता है कि उसे orc रेंडर करने की आवश्यकता है। आपने पहले ही एक orc मॉडल लोड किया होगा, जिसे रेंडरर तब प्रदर्शित करना जानता है।

यह आपकी आवश्यकताओं को पूरा करना चाहिए। ग्राफिक प्रतिनिधित्व और तर्क युग्मित हैं , क्योंकि वे दोनों एक ही डेटा का उपयोग करते हैं। फिर भी वे अलग हैं , क्योंकि न तो दूसरे पर निर्भर हैं!

संपादित करें: और सिर्फ यह जवाब देने के लिए कि कोई ऐसा क्यों करेगा? क्योंकि यह आसान है सबसे सरल कारण है। आपको "इस तरह के और इस तरह के होने के बारे में सोचने की ज़रूरत नहीं है, मुझे अब ग्राफिक्स को अपडेट करना चाहिए"। इसके बजाय आप सामान बनाते हैं, और प्रत्येक फ्रेम खेल को देखता है कि वर्तमान में क्या हो रहा है, और इसे किसी तरह से व्याख्या करता है, जिससे आपको ऑन-स्क्रीन परिणाम मिलता है।


7

आपका शीर्षक आपके शरीर की सामग्री से अलग प्रश्न पूछता है। शीर्षक में, आप पूछते हैं कि तर्क और प्रतिपादन को अलग क्यों किया जाना चाहिए, लेकिन शरीर में आप तर्क / ग्राफिक्स / प्रतिपादन प्रणाली के कार्यान्वयन के लिए पूछते हैं।

दूसरा प्रश्न पहले से संबोधित किया गया है , इसलिए मैं पहले प्रश्न पर ध्यान केंद्रित करूंगा।

तर्क और प्रतिपादन को अलग करने के कारण:

  1. व्यापक रूप से आयोजित धारणा है कि वस्तुओं को एक काम करना चाहिए
  2. यदि आप 2D से 3D में जाना चाहते हैं तो क्या होगा? क्या होगा यदि आप प्रोजेक्ट के बीच में एक रेंडरिंग सिस्टम से दूसरे में बदलने का निर्णय लेते हैं? आप अपने सभी कोड के माध्यम से क्रॉल नहीं करना चाहते हैं और अपने गेम लॉजिक के बीच में भारी बदलाव करना चाहते हैं।
  3. आपके पास कोड के वर्गों को दोहराने का कारण होगा, जिसे आमतौर पर एक बुरा विचार माना जाता है।
  4. आप छोटे टुकड़ों के साथ व्यक्तिगत रूप से संवाद किए बिना प्रतिपादन या तर्क के संभावित विशाल swaths को नियंत्रित करने के लिए सिस्टम का निर्माण कर सकते हैं।
  5. क्या होगा यदि आप एक खिलाड़ी को एक मणि सौंपना चाहते हैं, लेकिन मणि के कितने पहलू हैं? यदि आपने अपने रेंडरिंग सिस्टम को अच्छी तरह से अमूर्त कर लिया है, तो आप महंगे रेंडरिंग ऑपरेशन के लिए इसे अलग-अलग दरों पर अपडेट कर सकते हैं।
  6. यह आपको उन चीजों के बारे में सोचने की अनुमति देता है जो वास्तव में आप क्या कर रहे हैं इससे कोई फर्क नहीं पड़ता। मैट्रिक्स के चारों ओर आपका मस्तिष्क क्यों बदल जाता है और ऑफ़सेट और स्क्रीन निर्देशांक को छिड़कता है जब आप करना चाहते हैं तो डबल-जंप मैकेनिक को लागू करना, कार्ड खींचना या तलवार से लैस करना है? आप चमकीले गुलाबी रंग में अपने सुसज्जित तलवार को प्रस्तुत करने वाले स्प्राइट का प्रतिनिधित्व नहीं करना चाहते हैं क्योंकि आप इसे अपने दाहिने हाथ से अपने बाईं ओर ले जाना चाहते थे।

OOP में नई वस्तुओं को तुरंत सेट करने की लागत होती है, लेकिन मेरे अनुभव में सिस्टम संसाधनों की लागत एक छोटी सी कीमत है जिसके बारे में सोचने और उन विशिष्ट चीजों को लागू करने की क्षमता है जो मुझे करने की आवश्यकता है।


6

यह जवाब केवल अंतर्ज्ञान का निर्माण करना है कि सीधे व्यावहारिक उदाहरणों को सुझाने के बजाय प्रतिपादन और तर्क को अलग करना क्यों महत्वपूर्ण है।

मान लेते हैं कि हमारे पास एक बड़ा हाथी है , कमरे में कोई भी पूरे हाथी को नहीं देख सकता है। शायद हर कोई भी इस बात से असहमत है कि यह वास्तव में क्या है। क्योंकि हर कोई हाथी का एक अलग हिस्सा देखता है और केवल उस हिस्से से निपट सकता है। लेकिन अंत में यह इस तथ्य को नहीं बदलता है कि यह एक बड़ा हाथी है।

हाथी अपने सभी विवरणों के साथ खेल वस्तु का प्रतिनिधित्व करता है। लेकिन किसी को वास्तव में हाथी (गेम ऑब्जेक्ट) के बारे में सब कुछ जानने की जरूरत नहीं है कि वह अपनी कार्यक्षमता करने में सक्षम हो।

गेम लॉजिक को युग्मित करना और प्रतिपादन वास्तव में ऐसा है जैसे हर कोई पूरे हाथी को देखता है। अगर कुछ बदला है तो हर किसी को इसके बारे में जानने की जरूरत है। जबकि ज्यादातर मामलों में उन्हें केवल उस भाग को देखने की आवश्यकता होती है जिसमें वे केवल रुचि रखते हैं। यदि किसी व्यक्ति ने उस व्यक्ति के बारे में जानता है जो केवल उस परिवर्तन के परिणाम के बारे में दूसरे व्यक्ति को बताने की आवश्यकता है, तो वह केवल उसके लिए महत्वपूर्ण है (इसे संदेश या इंटरफेस के माध्यम से संचार के रूप में सोचें)।

यहाँ छवि विवरण दर्ज करें

आपके द्वारा उल्लेखित बिंदु ड्रॉ बैक नहीं हैं, वे केवल ड्रॉ बैक हैं यदि इंजन में अधिक निर्भरता थी, तो दूसरे शब्दों में, सिस्टम हाथी के कुछ हिस्सों को देखते हैं जितना उन्हें होना चाहिए। और इसका मतलब है कि इंजन "सही ढंग से" डिजाइन नहीं किया गया था।

आपको केवल औपचारिक परिभाषा के साथ सिंक्रनाइज़ेशन की आवश्यकता है यदि आप एक बहु-थ्रेडेड इंजन का उपयोग कर रहे हैं जहां यह तर्क और रेंडरिंग को दो अलग-अलग थ्रेड्स में रखता है, और यहां तक ​​कि एक इंजन जिसे सिस्टम के बीच बहुत अधिक सिंक्रनाइज़ेशन की आवश्यकता होती है, विशेष रूप से बहुत डिज़ाइन नहीं किया गया है।

अन्यथा, ऐसे मामले से निपटने का प्राकृतिक तरीका, सिस्टम को इनपुट / आउटपुट के रूप में डिजाइन कर रहा है। अद्यतन तर्क करता है और परिणाम को आउटपुट करता है। रेंडरिंग केवल अपडेट के परिणामों के साथ फ़ीड है। आपको वास्तव में सब कुछ उजागर करने की आवश्यकता नहीं है। आप केवल एक इंटरफ़ेस को उजागर करते हैं जो दो चरणों के बीच संचार करता है। इंजन के विभिन्न हिस्सों के बीच संचार अमूर्त (इंटरफेस) और / या संदेशों के माध्यम से होना चाहिए। किसी भी आंतरिक तर्क या स्थिति को उजागर नहीं किया जाना चाहिए।

आइए विचार को समझाने के लिए एक सरल दृश्य ग्राफ उदाहरण लेते हैं।

अद्यतन करना आमतौर पर एक लूप के माध्यम से किया जाता है जिसे गेम लूप कहा जाता है (या संभवतः कई गेम लूप के माध्यम से, प्रत्येक एक अलग थ्रेड में चल रहा है)। एक बार लूप ने कभी गेम ऑब्जेक्ट को अपडेट किया। इसे केवल मैसेजिंग या इंटरफेस के माध्यम से बताना होगा कि ऑब्जेक्ट 1 और 2 जहां अपडेट किए गए हैं और इसे अंतिम रूपांतर के साथ खिलाएं।

रेंडरिंग सिस्टम केवल अंतिम परिवर्तन लेता है और यह नहीं जानता कि वास्तव में ऑब्जेक्ट के बारे में क्या बदला है (उदाहरण के लिए विशिष्ट टक्कर आदि)। अब उस ऑब्जेक्ट को रेंडर करने के लिए उसे केवल उस ऑब्जेक्ट की आईडी और अंतिम ट्रांसफॉर्म की जरूरत होती है। उसके बाद रेंडरर मेष और अंतिम रूपांतर के साथ रेंडरिंग एपीआई को कुछ और जाने बिना खिला देगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.