गेम ऑब्जेक्ट्स को एक दूसरे के बारे में कैसे पता होना चाहिए?


18

मुझे गेम ऑब्जेक्ट्स को व्यवस्थित करने का एक तरीका खोजना मुश्किल है ताकि वे पॉलीमॉर्फिक हों लेकिन एक ही समय में पॉलीमॉर्फिक नहीं।

यहाँ एक उदाहरण है: यह मानते हुए कि हम अपनी सभी वस्तुओं को चाहते हैं update()औरdraw() । ऐसा करने के लिए हमें एक आधार वर्ग को परिभाषित करने की आवश्यकता है, GameObjectजिसमें वे दो आभासी शुद्ध विधियाँ हों और बहुरूपता को अंदर आने दें:

class World {
private:
    std::vector<GameObject*> objects;
public:
    // ...
    update() {
        for (auto& o : objects) o->update();
        for (auto& o : objects) o->draw(window);
    }
};

अद्यतन पद्धति को ध्यान में रखना चाहिए कि विशिष्ट वर्ग की वस्तु को अद्यतन करने के लिए किस राज्य की आवश्यकता है। तथ्य यह है कि प्रत्येक वस्तुओं को उनके आसपास की दुनिया के बारे में जानने की जरूरत है। उदाहरण के लिए:

  • एक खदान को यह जानना चाहिए कि क्या कोई उसके साथ टकरा रहा है
  • एक सैनिक को पता होना चाहिए कि क्या किसी अन्य टीम का सैनिक निकटता में है
  • एक ज़ोंबी को पता होना चाहिए कि एक त्रिज्या के भीतर निकटतम मस्तिष्क कहां है

निष्क्रिय अंतःक्रियाओं के लिए (पहले वाले की तरह) मैं सोच रहा था कि टकराव का पता लगा सकता है कि टकराव के विशिष्ट मामलों में वस्तु के साथ क्या करना है? on_collide(GameObject*)

अधिकांश अन्य informations (अन्य दो उदाहरणों की तरह) को खेल की दुनिया के लिए updateविधि द्वारा पारित किया जा सकता है। अब दुनिया उनकी प्रकार के आधार पर वस्तुओं भेद नहीं करता है, तो क्या वास्तव में यह एक आदर्श के साथ वापस आ जाएगी (यह एक एकल बहुरूपी कंटेनर में सभी वस्तु संग्रहीत करता है) world.entities_in(center, radius)के एक कंटेनर है GameObject*। लेकिन निश्चित रूप से सैनिक अपनी टीम के अन्य सैनिकों पर हमला नहीं करना चाहता है और एक ज़ोंबी अन्य लाश के बारे में बात नहीं करता है। इसलिए हमें व्यवहार को अलग करने की जरूरत है। एक समाधान निम्नलिखित हो सकता है:

void TeamASoldier::update(const World& world) {
    auto list = world.entities_in(position, eye_sight);
    for (const auto& e : list)
        if (auto enemy = dynamic_cast<TeamBSoldier*>(e))
            // shoot towards enemy
}

void Zombie::update(const World& world) {
    auto list = world.entities_in(position, eye_sight);
    for (const auto& e : list)
        if (auto enemy = dynamic_cast<Human*>(e))
            // go and eat brain
}

लेकिन निश्चित रूप से dynamic_cast<>प्रति फ्रेम की संख्या बहुत अधिक हो सकती है, और हम सभी जानते हैं कि कितना धीमा dynamic_castहो सकता है। यही समस्या इस पर भी लागू होती हैon_collide(GameObject*) प्रतिनिधि पर हमने पहले चर्चा की थी।

तो यह कोड को व्यवस्थित करने का आदर्श तरीका क्या है ताकि वस्तुओं को अन्य वस्तुओं के बारे में पता चल सके और उन्हें अनदेखा करने या अपने प्रकार के आधार पर कार्रवाई करने में सक्षम हो सके?


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

मैं गेम लॉजिक के लिए टाइप सिस्टम का उपयोग करने के खिलाफ सलाह दूंगा। उदाहरण के लिए, के परिणाम के आधार पर dynamic_cast<Human*>, ए की तरह कुछ लागू करें bool GameObject::IsHuman(), जो falseडिफ़ॉल्ट रूप से लौटता है , लेकिन कक्षा trueमें वापस जाने के लिए ओवरराइड होता है Human
कॉंगसबोंगस

एक अतिरिक्त: आप लगभग कभी भी एक-दूसरे को उन वस्तुओं की एक टन वस्तु नहीं भेज सकते जो उनकी रुचि हो। यह एक स्पष्ट अनुकूलन है जिसे आपको वास्तव में विचार करना होगा।
तियोड्रोन

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

4
@ जेफ्री: आदर्श रूप से आप टाइप-विशिष्ट कोड नहीं लिखते हैं। आप इंटरफ़ेस- विशिष्ट कोड (सामान्य अर्थ में "इंटरफ़ेस") लिखते हैं । एक के लिए आपका तर्क TeamASoldierऔर TeamBSoldierवास्तव में समान है - किसी अन्य टीम पर किसी को भी गोली मार दी। अन्य सभी संस्थाओं को GetTeam()इसकी सबसे विशिष्ट पर एक विधि की आवश्यकता होती है और, कॉंग्सबोंगस के उदाहरण से, कि आगे भी IsEnemyOf(this)इंटरफ़ेस के प्रकार में अमूर्त किया जा सकता है। कोड को सैनिकों, लाशों, खिलाड़ियों आदि के वर्गीकरण वर्गीकरण के बारे में परवाह करने की आवश्यकता नहीं है, बातचीत पर ध्यान दें, न कि प्रकारों पर।
सीन मिडिलिच

जवाबों:


11

अपने आप में प्रत्येक इकाई के निर्णय लेने को लागू करने के बजाय, आप वैकल्पिक रूप से नियंत्रक-पैटर्न के लिए जा सकते हैं। आपके पास केंद्रीय नियंत्रक कक्षाएं होंगी जो सभी वस्तुओं (जो उनके लिए मायने रखती हैं) से अवगत हैं और उनके व्यवहार को नियंत्रित करती हैं।

एक मूवमेंटकंट्रोलर उन सभी ऑब्जेक्ट्स की मूवमेंट को हैंडल करेगा जो मूव कर सकते हैं (रुट फाइंडिंग, अपडेट मूवमेंट ऑन द करेंट मूवमेंट वेक्टर्स)।

एक MineBehaviorController सभी खानों और सभी सैनिकों की जांच करेगा, और एक सैनिक को बहुत करीब आने पर विस्फोट करने के लिए एक खदान की आज्ञा देगा।

एक ZombieBehaviorController अपने आसपास के क्षेत्र में सभी लाश और सैनिकों की जांच करेगा, प्रत्येक ज़ोंबी के लिए सबसे अच्छा लक्ष्य चुनें, और इसे वहां स्थानांतरित करने और इसे हमला करने के लिए आज्ञा दें (यह कदम खुद MovementController द्वारा नियंत्रित किया जाता है)।

एक SoldeBehaviorController पूरी स्थिति का विश्लेषण करेगा और फिर सभी सैनिकों के लिए सामरिक निर्देशों के साथ आएगा (आप वहां जाते हैं, आप इसे शूट करते हैं, आप उस आदमी को ठीक करते हैं ...)। इन उच्च-स्तरीय कमांडों का वास्तविक निष्पादन निम्न-स्तरीय नियंत्रकों द्वारा भी किया जाएगा। जब आप इसमें कुछ प्रयास करते हैं, तो आप AI को काफी स्मार्ट सहकारी निर्णयों में सक्षम बना सकते हैं।


1
संभवतः इसे "सिस्टम" के रूप में भी जाना जाता है जो एक इकाई-घटक वास्तुकला में कुछ प्रकार के घटकों के लिए तर्क का प्रबंधन करता है।
तेओद्रोन

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

1
@ जेफ्री "जो एक सी-स्टाइल समाधान की तरह लगता है" - जब यह सच होगा, तब भी यह एक बुरी चीज क्यों होगी? अन्य चिंताएँ मान्य हो सकती हैं, लेकिन उनके लिए समाधान हैं। दुर्भाग्य से एक टिप्पणी उनमें से प्रत्येक को ठीक से संबोधित करने के लिए बहुत कम है।
फिलिप

1
@Jefffrey उस दृष्टिकोण का उपयोग कर रहा है जहाँ घटकों में कोई तर्क नहीं होता है और "सिस्टम" सभी तर्कों को संभालने के लिए ज़िम्मेदार होते हैं जो घटकों के बीच निर्भरता पैदा नहीं करते हैं और न ही इसके लिए सुपर कॉम्प्लेक्स मैसेजिंग सिस्टम (कम से कम, लगभग उतना ही जटिल) की आवश्यकता नहीं होती है । उदाहरण के लिए देखें: gamadu.com/artemis/tutorial.html

1

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

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

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

इसलिए आप प्रति फ्रेम एक बार क्या करते हैं। विश्व स्तर पर वर्तमान वस्तुओं की स्थिति को बफर करें। 2. खुद और बफर के आधार पर सभी वस्तुओं को अपडेट करें। 3. अपनी वस्तुओं को आकर्षित करें और फिर बफर को नवीनीकृत करने के साथ शुरू करें।


1

एक घटक आधारित प्रणाली का उपयोग करें, जिसमें आपके पास एक नंगे बॉट्स गेम ऑबजेक्ट है जिसमें 1 या अधिक घटक होते हैं जो उनके व्यवहार को परिभाषित करते हैं।

उदाहरण के लिए, कुछ ऑब्जेक्ट को हर समय (एक प्लेटफ़ॉर्म) बाएँ और दाएँ ले जाने के लिए माना जाता है, आप इस तरह का एक घटक बना सकते हैं और इसे गेमऑबजेक्ट में संलग्न कर सकते हैं।

अब कहते हैं कि एक गेम ऑब्जेक्ट को धीरे-धीरे हर समय घुमाने के लिए माना जाता है, आप एक अलग घटक बना सकते हैं जो इसे करता है और इसे गेमऑउट में संलग्न करता है।

क्या होगा अगर आप एक पारंपरिक मंच उत्तराधिकार में घुमाए जाने वाले प्लेटफ़ॉर्म को घुमाना चाहते हैं, जो कि डुप्लिकेट कोड के बिना करना मुश्किल हो जाता है।

इस प्रणाली की ख़ासियत यह है कि, रोटेटेबल या मूविंगप्लेकॉर्डर क्लास होने के बजाय, आप उन दोनों घटकों को गेमऑबजेक्ट में संलग्न करते हैं और अब आपके पास एक मूविंगप्लास्ट है जो ऑटोरोटेट्स है।

सभी घटकों के पास एक संपत्ति है, 'आवश्यक' की आवश्यकता है, जबकि सच है, गेमऑब्जेक्ट ने कहा कि घटक के लिए 'अद्यतन' विधि होगी। उदाहरण के लिए, मान लें कि आपके पास एक ड्रैग करने योग्य घटक है, माउस-डाउन पर यह घटक (यदि यह गेमऑबजेक्ट से अधिक था) 'trueUpdate' को सही पर सेट कर सकता है, और फिर माउस-अप पर इसे गलत पर सेट कर सकता है। जब माउस नीचे हो तभी माउस का पालन करना।

टोनी हॉक प्रो स्केटर डेवलपर्स में से एक पर डिफैक्टो लिखा है, और यह अच्छी तरह से पढ़ने लायक है: http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/


1

वंशानुक्रम पर अनुकूल रचना।

इससे अलग मेरी सबसे मजबूत सलाह यह होगी: "मैं चाहता हूं कि यह सर्वोच्च रूप से लचीला हो"। लचीलापन महान है, लेकिन याद रखें कि किसी भी स्तर पर, किसी भी परिमित प्रणाली जैसे कि एक खेल में, परमाणु भाग होते हैं जिनका उपयोग संपूर्ण निर्माण के लिए किया जाता है। एक तरह से या किसी अन्य, आपका प्रसंस्करण उन पूर्व-परिभाषित, परमाणु प्रकारों पर निर्भर करता है। दूसरे शब्दों में, "किसी भी" प्रकार के डेटा (यदि संभव हो तो) के लिए खानपान आपको लंबे समय तक मदद नहीं करेगा, अगर आपके पास इसे संसाधित करने के लिए कोड नहीं है। मूल रूप से, सभी कोड को ज्ञात विशिष्टताओं के आधार पर डेटा को पार्स / प्रोसेस करना चाहिए ... जिसका अर्थ है प्रकारों का पूर्वनिर्धारित सेट। कितना बड़ा सेट? आप पर निर्भर करता है।

यह लेख एक मजबूत और प्रदर्शनकारी इकाई-घटक वास्तुकला के माध्यम से खेल के विकास में वंशानुक्रम पर रचना के सिद्धांत में अंतर्दृष्टि प्रदान करता है।

पूर्वनिर्धारित घटकों के कुछ सुपरसेट के (अलग-अलग) उपसमुच्चयों से संस्थाओं के निर्माण के द्वारा, आप उन अभिनेताओं के घटकों को पढ़कर, अपने एआई कंक्रीट, दुनिया को समझने और उनके आसपास के अभिनेताओं के टुकड़ों को प्रस्तुत करते हैं।


1

व्यक्तिगत रूप से मैं ड्रॉ फ़ंक्शन को ऑब्जेक्ट क्लास से बाहर रखने की सलाह देता हूं। मैं ऑब्जेक्ट को लोकेशन से बाहर रखने की सलाह भी देता हूं।

वह ड्रा () विधि OpenGL, OpenGL ES, Direct3D दोनों में से निम्न स्तर प्रतिपादन एपीआई के साथ काम करने जा रही है, उन API या इंजन API पर आपकी रैपिंग परत। यह हो सकता है कि आपको बीच में स्वैप करना पड़े (यदि आप उदाहरण के लिए OpenGL + OpenGL ES + Direct3D का समर्थन करना चाहते थे।

गेमऑबजेक्ट में बस मूल जानकारी होनी चाहिए, जैसे कि विज़ुअल उपस्थिति जैसे कि मेष या हो सकता है कि एक बड़ा बंडल जिसमें shader निविष्टियाँ, एनीमेशन स्थिति और इतने पर शामिल हों।

इसके अलावा, आप एक लचीला ग्राफिक्स पाइपलाइन चाहते हैं। यदि आप कैमरे पर उनकी दूरी के आधार पर वस्तुओं को ऑर्डर करना चाहते हैं तो क्या होगा। या उनकी सामग्री प्रकार। यदि आप 'चयनित' ऑब्जेक्ट को एक अलग रंग बनाना चाहते हैं तो क्या होगा। इसके बारे में अगर वास्तव में सू के रूप में आप एक वस्तु पर एक आकर्षित समारोह कहते हैं, इसके बजाय यह इसे प्रस्तुत करने के लिए कार्रवाई की एक कमांड सूची में डालता है (सूत्रण के लिए आवश्यक हो सकता है)। आप दूसरी प्रणाली के साथ उस तरह का काम कर सकते हैं लेकिन यह एक PITA है।

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

आपके स्तर / विखंडू / क्षेत्र / नक्शे / हब / पूरे / जो कुछ भी एक स्थानिक सूचकांक दिया जाता है, इसमें ऑब्जेक्ट शामिल होते हैं और उन्हें समन्वित प्रश्नों के आधार पर लौटाते हैं और एक साधारण सूची या ओक्ट्री जैसी कोई चीज हो सकती है। यह भौतिक विज्ञान के दृश्य के रूप में 3rd पार्टी भौतिकी इंजन द्वारा कार्यान्वित कुछ के लिए एक आवरण भी हो सकता है। यह आपके लिए "सभी वस्तुओं को क्वेरी करने की अनुमति देता है जो कैमरे के दृश्य में हैं उनके आसपास कुछ अतिरिक्त क्षेत्र के साथ" या सरल गेम के लिए जहां आप बस पूरी सूची को हथियाने के लिए सब कुछ प्रस्तुत कर सकते हैं।

स्पेसियल इंडेक्स में वास्तविक स्थिति की जानकारी नहीं होती है। वे अन्य वस्तुओं के स्थान के संबंध में पेड़ों की संरचनाओं में वस्तुओं को संग्रहीत करके काम करते हैं। वे एक प्रकार की हानिपूर्ण कैश के रूप में हो सकते हैं, जो किसी वस्तु की त्वरित खोज को उसकी स्थिति के आधार पर अनुमति देता है। आपके वास्तविक X, Y, Z निर्देशांक की नकल करने की कोई वास्तविक आवश्यकता नहीं है। अगर आप रखना चाहते हैं तो आप कह सकते हैं

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

जब आप किसी Object को Level पर जोड़ते हैं। यह निम्नलिखित कार्य करेगा:

1) एक स्थान संरचना बनाएँ:

 class Location { 
     float x, y, z; // Or a special Coordinates class, or a vec3 or whatever.
     SpacialIndex& spacialIndex; // Note this could be the area/level/map/whatever here
 };

यह तीसरे पक्ष के भौतिकी इंजन में किसी वस्तु के संदर्भ में भी हो सकता है। या यह किसी अन्य स्थान (एक ट्रैकिंग कैमरा या संलग्न वस्तु या उदाहरण के लिए) के संदर्भ के साथ एक ऑफसेट निर्देशांक हो सकता है। बहुरूपता के साथ यह या तो निर्भर हो सकता है अगर यह एक स्थिर या गतिशील वस्तु है। निर्देशांक अद्यतन किया जाता है जब यहाँ स्थानिक सूचकांक के लिए एक संदर्भ रखने के द्वारा भी स्थानिक सूचकांक हो सकता है।

यदि आप गतिशील मेमोरी आवंटन के बारे में चिंतित हैं, तो मेमोरी पूल का उपयोग करें।

2) अपनी वस्तु, उसके स्थान और दृश्य ग्राफ के बीच एक बंधन / लिंकिंग।

typedef std::pair<Object, Location> SpacialBinding.

3) बाइंडिंग को उचित बिंदु पर स्तर के अंदर स्थानिक सूचकांक में जोड़ा जाता है।

जब आप रेंडर करने की तैयारी कर रहे हैं।

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

2) कैमरे के SpacialBinding जाओ।

3) बाइंडिंग से स्पेसियल इंडेक्स प्राप्त करें।

4) कैमरे को दिखाई देने वाली (संभवतः) वस्तुओं को क्वेरी करें।

5A) आपको दृश्य जानकारी संसाधित करने की आवश्यकता है। GPU और इतने पर अपलोड किए गए टेक्स्ट। यह अग्रिम में किया जाएगा (जैसे कि लेवल लोड पर), लेकिन शायद रनटाइम पर किया जा सकता है (एक खुली दुनिया के लिए, आप सामान तब लोड कर सकते हैं जब आप एक चंक के पास होते हैं, लेकिन अभी भी अग्रिम में किया जाना चाहिए)।

5B) वैकल्पिक रूप से एक कैश्ड रेंडर ट्री का निर्माण करें, यदि आप बाद में समय पर दिखाई दे सकते हैं तो आस-पास की वस्तुओं को गहराई / सामग्री के प्रकार या ट्रैक करना चाहते हैं। अन्यथा आप केवल स्थानिक सूचकांक को क्वेरी कर सकते हैं यह आपके खेल / प्रदर्शन आवश्यकताओं पर निर्भर करेगा।

आपके रेंडरर को एक रेंडरबाइंडिंग ऑब्जेक्ट की आवश्यकता होगी जो ऑब्जेक्ट, निर्देशांक के बीच लिंक करेगा

class RenderBinding {
    Object& object;
    RenderInformation& renderInfo;
    Location& location // This could just be a coordinates class.
}

फिर जब आप रेंडर करते हैं, तो बस सूची चलाएं।

मैंने ऊपर संदर्भों का उपयोग किया है, लेकिन वे स्मार्ट पॉइंटर्स, रॉ पॉइंटर्स, ऑब्जेक्ट हैंडल आदि हो सकते हैं।

संपादित करें:

class Game {
    weak_ptr<Camera> camera;
    Level level1;

    void init() {
        Camera camera(75.0_deg, 1.025_ratio, 1000_meters);
        auto template_player = loadObject("Player.json")
        auto player = level1.addObject(move(player), Position(1.0, 2.0, 3.0));
        level1.addObject(move(camera), getRelativePosition(player));

        auto template_bad_guy = loadObject("BadGuy.json")
        level1.addObject(template_bad_guy, {10, 10, 20});
        level1.addObject(template_bad_guy, {10, 30, 20});
        level1.addObject(move(template_bad_guy), {50, 30, 20});
    }

    void render() {
        camera->getFrustrum();
        auto level = camera->getLocation()->getLevel();
        auto object = level.getVisible(camera);
        for(object : objects) {
            render(objects);
        }
    }

    void render(Object& object) {
        auto ri = object.getRenderInfo();
        renderVBO(ri.getVBO());
    }

    Object loadObject(string file) {
        Object object;
        // Load file from disk and set the properties
        // Upload mesh data, textures to GPU. Load shaders whatever.
        object.setHitPoints(// values from file);
        object.setRenderInfo(// data from 3D api);
    }
}

class Level {
    Octree octree;
    vector<ObjectPtr> objects;
    // NOTE: If your level is mesh based there might also be a BSP here. Or a hightmap for an openworld
    // There could also be a physics scene here.
    ObjectPtr addObject(Object&& object, Position& pos) {
        Location location(pos, level, object);
        objects.emplace_back(object);
        object->setLocation(location)
        return octree.addObject(location);
    }
    vector<Object> getVisible(Camera& camera) {
        auto f = camera.getFtrustrum();
        return octree.getObjectsInFrustrum(f);
    }
    void updatePosition(LocationPtr l) {
        octree->updatePosition(l);
    }
}

class Octree {
    OctreeNode root_node;
    ObjectPtr add(Location&& object) {
        return root_node.add(location);
    }
    vector<ObjectPtr> getObjectsInRadius(const vec3& position, const float& radius) { // pass to root_node };
    vector<ObjectPtr> getObjectsinFrustrum(const FrustrumShape frustrum;) {//...}
    void updatePosition(LocationPtr* l) {
        // Walk up from l.octree_node until you reach the new place
        // Check if objects are colliding
        // l.object.CollidedWith(other)
    }
}

class Object {
    Location location;
    RenderInfo render_info;
    Properties object_props;
    Position getPosition() { return getLocation().position; }
    Location getLocation() { return location; }
    void collidedWith(ObjectPtr other) {
        // if other.isPickup() && object.needs(other.pickupType()) pick it up, play sound whatever
    }
}

class Location {
    Position position;
    LevelPtr level;
    ObjectPtr object;
    OctreeNote octree_node;
    setPosition(Position position) {
        position = position;
        level.updatePosition(this);
    }
}

class Position {
    vec3 coordinates;
    vec3 rotation;
}

class RenderInfo {
    AnimationState anim;
}
class RenderInfo_OpenGL : public RenderInfo {
    GLuint vbo_object;
    GLuint texture_object;
    GLuint shader_object;
}

class Camera: public Object {
    Degrees fov;
    Ratio aspect;
    Meters draw_distance;
    Frustrum getFrustrum() {
        // Use above to make a skewed frustum box
    }
}

चीजों को एक-दूसरे को 'जागरूक' बनाने के लिए। यही है टकराव का पता लगाना। इसे संभवत: ऑक्ट्री में लागू किया जाएगा। आपको अपने मुख्य ऑब्जेक्ट में कुछ कॉलबैक प्रदान करने की आवश्यकता होगी। यह सामान बुलेट जैसे एक उचित भौतिकी इंजन द्वारा सबसे अच्छा नियंत्रित किया जाता है। उस स्थिति में बस Octree को PhysicsScene से बदलें और CollisionMesh.getPosition () जैसी किसी चीज़ की लिंक के साथ स्थिति।


वाह, यह बहुत अच्छा लग रहा है। मुझे लगता है कि मैंने मूल विचार को समझ लिया है, लेकिन अधिक उदाहरण के बिना मैं इस बारे में बाहरी विचार प्राप्त नहीं कर सकता। क्या आपके पास इस पर कोई और संदर्भ या जीवंत उदाहरण हैं? (मैं इस उत्तर को इस बीच कुछ समय तक पढ़ता रहूंगा)।
जूता

वास्तव में कोई उदाहरण नहीं है, यह वही है जो मैं समय मिलने पर करने की योजना बना रहा हूं। मैं समग्र कक्षाओं में कुछ और जोड़ूंगा और देखूंगा कि क्या मदद मिलती है, यह है और यह है । यह ऑब्जेक्ट क्लास के बारे में अधिक है कि वे कैसे संबंधित या प्रतिपादन करते हैं। जैसा कि मैंने इसे स्वयं कार्यान्वित नहीं किया है, ऐसे नुकसान हो सकते हैं, बिट्स जिन्हें वर्क आउट या प्रदर्शन सामग्री की आवश्यकता होती है, लेकिन मुझे लगता है कि समग्र संरचना ठीक है।
डेविड सी। बिशप
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.