जब मैं मर जाता हूं तो मैं अपने गेम लूप से एक इकाई को कैसे निकालूं?


16

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

वैसे भी, मेरा सवाल है, जब एक इकाई को नष्ट कर दिया जाता है, तो मुझे इसे सूची से कैसे निकालना चाहिए? मैं इसकी स्थिति को कम कर सकता हूं, इसे अलग कर सकता हूं या "यह कहने के लिए कि मुझे छोड़ दो, मैं मर चुका हूं।" मैं अपनी संस्थाओं को पूल कर रहा हूं, इसलिए एक ऐसी संस्था जो मर चुकी है, कुछ बिंदु पर फिर से जीवित होने की संभावना है। प्रत्येक प्रकार के संग्रह के लिए मेरी सबसे अच्छी रणनीति क्या है, और संग्रह प्रकार और निष्कासन विधि का कौन सा संयोजन सबसे अच्छा काम करेगा?


एक वेक्टर की लंबाई तय नहीं है, लेकिन यह टाइप किया गया है, और यह इसे ऐरे से बेहतर बनाता है। दोष यह है कि पहले से भरी हुई सूची को परिभाषित करने के लिए कोई त्वरित वाक्यविन्यास नहीं है, लेकिन आपको लगता है कि मुझे इसकी आवश्यकता नहीं है।
बार्ट वैन ह्युकेलोम

जवाबों:


13

मैं अलग-अलग सूचियों में सभी ऐड / रिमूव को स्टोर करूँगा और अपडेट-लूप के माध्यम से iterated करने के बाद उन ऑपरेशनों को करूँगा।


10

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


1
फ्लिक्सल के लिए +1। पुनर्चक्रण deadप्रदर्शन के साथ वास्तव में मदद करता है।
स्नो ब्लाइंड

3

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

बस यहाँ पहले से ही चर्चा की गई कुछ तकनीकों को संबोधित करने के लिए। यदि संस्थाओं का आदेश महत्वपूर्ण है, तो एक मृत ध्वज आपको अगले फ्रेम पर अपने अपडेट लूप के दौरान विभाजित करने की अनुमति दे सकता है। जैसे। बहुत ही सरल छद्म कोड:

void updateGame()
{
  // updateEntities()
  Entity* pSrcEntity = &mEntities[0];
  Entity* pDstEntity = &mEntities[0];
  newNumEntities = 0;
  for (int i = 0; i < numEntities; i++)
  {
    if (!pSrcEntity->isDead)
    {
       // could be inline but whatever.
       updateEntity(pDstEntity, pSrcEntity);
       // if entity just died, don't update the pDstEntity pointer, 
       // and just let the next entity updated overwrite it.
       if (!pDstEntity->isDead)
       {
          pDstEntity++;
          newNumEntities++;
       }
    }
    pSrcEntity++;
  }
}
numEntities = newNumEntities;

ये हैं इस योजना की विशेषताएं:

  • संस्थाओं की प्राकृतिक कॉम्पैक्टनेस (यद्यपि एक इकाई स्लॉट से पहले संभवत: 1 फ्रेम विलंबता के साथ)।
  • कोई यादृच्छिक पुन: आदेश देने वाले मुद्दे नहीं।
  • जबकि दोगुनी लिंक की गई सूचियों में O (1) सम्मिलन / विलोपन है, लेकिन इष्टतम कैश विलंबता छिपाना के लिए प्रीफ़ेट करना बहुत कठिन है। उन्हें एक कॉम्पैक्ट एरे में रखने से ब्लॉक प्रीफेचिंग तकनीकों को अच्छी तरह से काम करने की अनुमति मिलती है।
  • बहु-ऑब्जेक्ट विनाश के मामले में, आपको ऑर्डर और कॉम्पैक्टनेस बनाए रखने के लिए निरर्थक शिफ्ट-कॉपी करने की ज़रूरत नहीं है (यह सब अपडेट पास के दौरान एक बार हो जाता है)
  • आप उन डेटा को छूने का लाभ उठाते हैं जिन्हें अपडेट के दौरान पहले से कैश में होना चाहिए।
  • यदि आपके स्रोत और गंतव्य इकाई के कवि अलग-अलग सरणियों के लिए हैं तो यह अच्छी तरह से काम करता है। तब आप मल्टीकोर / ईजी का लाभ लेने के लिए अपनी इकाई एरेज़ को डबल-बफर कर सकते हैं। फ्रेम एन के लिए संस्थाओं को अपडेट करने / लिखने वाला एक धागा, जबकि दूसरा धागा फ्रेम एन -1 के लिए पिछले फ्रेम की संस्थाओं का प्रतिपादन कर रहा है।
  • कॉम्पैक्टनेस का अर्थ है कि अधिक सीपीयू काम करने वाले ऑफलोडिंग जैसे के लिए एक विषम प्रोसेसर के लिए पूरे डीएमए के लिए बहुत आसान है। एसपीयू या जीपीयू।

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

2

मेरे सामान्य प्रोग्रामिंग अनुभव के संदर्भ में, आमतौर पर सभी मौजूदा तत्वों को एक साथ स्थानांतरित करने के लिए, splicing एक धीमा ऑपरेशन है। मुझे लगता है कि इसे शून्य पर सेट करना यहां सबसे अच्छा समाधान होगा ; एक मृत झंडा काम करेगा, लेकिन आपको यह ध्यान रखने की आवश्यकता है कि यह आपके कोड को गन्दा न करे।

हम वास्तव में वास्तव में हालांकि, वास्तव में चैटरूम में संसाधन पूलिंग के बारे में बात कर रहे थे। यह बहुत अच्छा अभ्यास है, और सुनने के लिए अच्छा है कि आप ऐसा कर रहे हैं। :)


1
यदि अपडेट ऑर्डर महत्वपूर्ण नहीं है, तो पिछली इकाई को वर्तमान सूचकांक में स्थानांतरित करने और अपने पूल की संख्या और पुनरावृत्ति सूचकांक को कम करने के रूप में splicing सरल होना चाहिए।
काज

वाह, बहुत अच्छी बात काज! :)
Ricket

2

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

जब भी आप लिंक की गई सूची से किसी आइटम को हटाते हैं, तो आप इसे ऑब्जेक्ट के एक पूल में जोड़ सकते हैं, जिसे फिर मेमोरी-आवंटन पर सहेजने के लिए पुन: चक्रित किया जा सकता है।

मैंने कई प्रोजेक्ट्स में पॉलीगॉनल-डेटास्ट्रक्चर का उपयोग किया है और उनके साथ बहुत खुश हूं।

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


1
मुझे लगता है कि आप यहां एक डबल-लिंक्ड सूची का सुझाव देते हैं? (आगे पीछे)? इसके अलावा: क्या आप लिंक-तत्वों पर किसी प्रकार के पूल का सुझाव दे रहे हैं या आप गतिशील रूप से लिंक्ड सूची में प्रत्येक पॉइंटर धारक को आवंटित कर रहे हैं?
शमौन

हां, यह एक डबल-लिंक्ड-लिस्ट होना चाहिए जो उस कार्य के लिए सबसे उपयुक्त है। यह बात बताने के लिए धन्यवाद! वस्तुओं के पुन: उपयोग के बारे में: मैं एक विशेष पूलिंग क्लास / डेटास्ट्रक्चर के बारे में सोच रहा था, जो मांग पर नई वस्तुओं का निर्माण करता है या मौजूदा उदाहरणों का उपयोग करता है यदि पूल में कुछ हैं। इसलिए वास्तव में "मृत" वस्तुओं को सूची से हटाना और बाद में उपयोग के लिए पूल में जोड़ना अच्छा होगा।
बुमज़ैक 20

एक जुड़ी हुई सूची ठीक काम करेगी। संदेह से जुड़ी सूचियां केवल दोनों दिशाओं में पुनरावृत्ति का लाभ देती हैं। वर्तमान आइटम को हटाने के विकल्प के साथ एक एकल लिंक की गई सूची के माध्यम से पुनरावृति करने के लिए आपको पिछली प्रविष्टि का ट्रैक रखना होगा।
deft_code

@ कैस्पिन हां बिल्कुल। यदि आप एकल-लिंक्ड-लिस्ट का उपयोग कर रहे हैं, तो आपको पिछले नोड्स का ट्रैक रखने और nextहटाए जाने के बाद उनके पॉइंटर को नोड से लिंक करने की आवश्यकता है। यदि आप स्वयं ऐसा करने का झंझट नहीं चाहते हैं, तो एक डबल-लिंक्ड-लिस्ट डेटास्ट्रक्चर ऑफ़ चॉइस होगी।
बुमज़ैक

1

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

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


0

एक स्वच्छ और सामान्य समाधान जो मुझे लगता है कि एक लिबास में पाया जाता था, जो एक लॉक करने योग्य मानचित्र का उपयोग करता था।

आपके पास 2 ऑपरेशन हैं , lock()और unlock()जब आप नक्शे पर पुनरावृत्ति करेंगे lock(), तो अब इस बिंदु से हर ऑपरेशन जो मानचित्र को प्रभावी नहीं करता है, उसे CommandQueueकॉल करने पर बस एक धक्का दिया जाएगा unlock()

इसलिए किसी इकाई को हटाने से निम्नलिखित छद्म कोड होंगे:

void lockableMap::remove(std::string id) {
   if(isLocked) {
       commandQueue.add(new RemoveCommand(id));
   } else {
       //remove element from map
   }

और जब आप unlock()

isLocked = false
commandQueue.execute(this);

केवल एक चीज पर आपको विचार करना है कि आप केवल लूप के बाद इकाई को हटा देंगे।

EDIT: यह साइमन द्वारा प्रस्तावित समाधान है।



0

मेरे पास दो तरीके हैं।

जब आप किसी ऑब्जेक्ट को हटाने के लिए कहते हैं, तो यह वास्तव में दो झंडे सेट करता है:

1. कंटेनर को बताने के लिए कि कोई ऑब्जेक्ट हटा दिया गया है

2. कंटेनर को बताने के लिए कि किन वस्तुओं को हटाने का अनुरोध किया गया है

void object::deleteObject()
{
    container->objectHasBeenDeleted = true;
    isToDelete = true;
}

एक वस्तुओं की एक वेक्टर का उपयोग करना

std::vector<object*> objects;

फिर अपडेट फ़ंक्शन में, यह देखने के लिए जांचें कि क्या कोई ऑब्जेक्ट हटा दिया गया है और यदि सभी वस्तुओं के माध्यम से पुनरावृति होती है और हटाए गए ध्वज को हटा दें

void container::update()
{
    if (objectHasBeenDeleted)
    {
        std::vector<object*>::iterator ListIterator;
        for(ListIterator=objects.begin(); ListIterator!=objects.end();)
        {
            if( (*ListIterator)->isToDelete )
            {
                ListIterator = objects.erase(ListIterator);
                delete *ListIterator;
            }
            else {
                ++ListIterator;
            }
        }
    objectHasBeenDeleted = false;
    }
}

दो वस्तुओं के वेक्टर के ए (पॉइंटर से) का उपयोग करना।

std::vector<object*> *objects;

अपडेट फ़ंक्शन में, यदि किसी ऑब्जेक्ट को हटाना है, तो ऑब्जेक्ट्स के माध्यम से पुनरावृति करें और उन लोगों को जोड़ें जो एक नए वेक्टर में डिलीट नहीं होने हैं। ऑब्जेक्ट वेक्टर को हटाएं और पॉइंटर को नए वेक्टर में सेट करें

void container::update()
{
    if (objectHasBeenDeleted)
    {
        std::vector<object*> *newVector;
        unsigned long i;
        for (i = 0; i < objects->size(); i++)
        {
            if (!objects->at(i)->isToDelete)
            {
                newVector->push_back(objects->at(i));
            }
        }
        delete objects;
        objects = newVector;
        objectHasBeenDeleted = false;
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.