इसका उत्तर हमेशा एक सरणी या std :: वेक्टर का उपयोग करना है। लिंक की गई सूची या एक std :: मानचित्र जैसे प्रकार आमतौर पर खेलों में बिल्कुल भयावह होते हैं , और इसमें निश्चित रूप से गेम ऑब्जेक्ट्स के संग्रह जैसे मामले शामिल होते हैं।
आपको सरणी / वेक्टर में ऑब्जेक्ट्स को स्वयं (उन्हें इंगित नहीं करना) स्टोर करना चाहिए।
आप सन्निहित स्मृति चाहते हैं । आप वास्तव में यह चाहते हैं। गैर-सन्निहित स्मृति में किसी भी डेटा पर Iterating, सामान्य रूप से बहुत सारी कैश मिस करता है और कंपाइलर और CPU के लिए प्रभावी कैश प्रीफ़ेटिंग करने की क्षमता को हटा देता है। यह अकेले प्रदर्शन को मार सकता है।
आप स्मृति आबंटन और डील-डौल से भी बचना चाहते हैं। वे बहुत धीमी गति से होते हैं, यहां तक कि एक तेज मेमोरी आवंटन के साथ। मैंने देखा है कि प्रत्येक फ्रेम से कुछ सौ मेमोरी एलोकेशन हटाकर गेम को 10x FPS की टक्कर मिलती है। ऐसा नहीं लगता कि यह उतना बुरा होना चाहिए, लेकिन यह हो सकता है।
अंत में, अधिकांश डेटा संरचनाएं जिन्हें आप गेम ऑब्जेक्ट के प्रबंधन के लिए परवाह करते हैं, वे किसी सरणी या वेक्टर पर अधिक कुशलतापूर्वक लागू हो सकते हैं, जैसे कि वे एक पेड़ या सूची के साथ हो सकते हैं।
उदाहरण के लिए, गेम ऑब्जेक्ट को हटाने के लिए, आप स्वैप-एंड-पॉप का उपयोग कर सकते हैं। आसानी से कुछ के साथ लागू:
std::swap(objects[index], objects.back());
objects.pop_back();
आप केवल हटाए गए ऑब्जेक्ट को चिह्नित कर सकते हैं और अगली बार जब आप एक नई वस्तु बनाने की आवश्यकता होती है, तो एक स्वतंत्र सूची में उनके सूचकांक को डालते हैं, लेकिन स्वैप-एंड-पॉप करना बेहतर होता है। यह आपको सभी जीवित वस्तुओं पर लूप के लिए एक सरल कार्य करने देता है जिसमें लूप से अलग कोई शाखा नहीं है। बुलेट भौतिकी एकीकरण और इस तरह के लिए, यह एक महत्वपूर्ण प्रदर्शन को बढ़ावा दे सकता है।
इससे भी महत्वपूर्ण बात, आप स्लॉट मैप संरचना का उपयोग करते हुए स्थिर यूनिक से टेबल लुकअप की एक साधारण जोड़ी के साथ ऑब्जेक्ट पा सकते हैं।
आपकी गेम ऑब्जेक्ट में उनके मुख्य सरणी में एक इंडेक्स है। वे बहुत कुशलता से सिर्फ इस सूचकांक (एक नक्शा या एक हैश तालिका की तुलना में बहुत तेजी से) के साथ देखा जा सकता है। हालांकि, वस्तुओं को हटाते समय स्वैप और पॉप के कारण सूचकांक स्थिर नहीं होता है।
एक स्लॉट मैप में अप्रत्यक्ष की दो परतों की आवश्यकता होती है, लेकिन दोनों निरंतर सूचकांकों के साथ सरल सरणी लुकअप होते हैं। वो हैं तेज हैं । वास्तव में तेज।
मूल विचार यह है कि आपके पास तीन सरणियाँ हैं: आपकी मुख्य वस्तु सूची, आपकी अप्रत्यक्ष सूची और अप्रत्यक्ष सूची के लिए एक मुफ्त सूची। आपकी मुख्य वस्तु सूची में आपकी वास्तविक वस्तुएं होती हैं, जहां प्रत्येक वस्तु अपनी विशिष्ट आईडी जानती है। यूनिक आईडी एक इंडेक्स और एक वर्जन टैग से बना होता है। अप्रत्यक्ष सूची मुख्य वस्तु सूची के सूचकांकों की एक सरणी मात्र है। मुक्त सूची अप्रत्यक्ष सूची में सूचकांक का एक ढेर है।
जब आप मुख्य सूची में कोई ऑब्जेक्ट बनाते हैं, तो आप अप्रत्यक्ष सूची (मुक्त सूची का उपयोग करके) में अप्रयुक्त प्रविष्टि पाते हैं। अप्रत्यक्ष सूची में प्रविष्टि मुख्य सूची में अप्रयुक्त प्रविष्टि की ओर इशारा करती है। आप उस स्थान पर अपनी ऑब्जेक्ट को इनिशियलाइज़ करते हैं, और अपनी यूनिक आईडी को आपके द्वारा चुनी गई इनडायरेक्शन लिस्ट एंट्री के सूचकांक और मुख्य लिस्ट तत्व में मौजूदा वर्जन टैग, प्लस वन में सेट करते हैं।
जब आप किसी ऑब्जेक्ट को नष्ट करते हैं, तो आप स्वैप-एंड-पॉप को सामान्य करते हैं, लेकिन आप संस्करण संख्या भी बढ़ाते हैं। फिर आप अप्रत्यक्ष सूची इंडेक्स (ऑब्जेक्ट की यूनिक आईडी का हिस्सा) को भी मुफ्त सूची में जोड़ते हैं। किसी वस्तु को स्वैप-एंड-पॉप के हिस्से के रूप में ले जाने पर, आप अप्रत्यक्ष सूची में इसके नए स्थान पर इसकी प्रविष्टि को भी अपडेट करते हैं।
उदाहरण छद्म कोड:
Object:
int index
int version
other data
SlotMap:
Object objects[]
int slots[]
int freelist[]
int count
Get(id):
index = indirection[id.index]
if objects[index].version = id.version:
return &objects[index]
else:
return null
CreateObject():
index = freelist.pop()
objects[count].index = id
objects[count].version += 1
indirection[index] = count
Object* object = &objects[count].object
object.initialize()
count += 1
return object
Remove(id):
index = indirection[id.index]
if objects[index].version = id.version:
objects[index].version += 1
objects[count - 1].version += 1
swap(objects[index].data, objects[count - 1].data)
अप्रत्यक्ष परत आपको एक स्थिर पहचानकर्ता (इंडेक्स इनडायरेक्शन लेयर, जहाँ प्रविष्टियाँ नहीं चलती हैं) को एक संसाधन के लिए अनुमति देता है जो संघनन (मुख्य वस्तु सूची) के दौरान स्थानांतरित हो सकता है।
संस्करण टैग आपको किसी ऑब्जेक्ट को ID संग्रहीत करने की अनुमति देता है जिसे हटाया जा सकता है। उदाहरण के लिए, आपके पास आईडी (10,1) है। इंडेक्स 10 के साथ ऑब्जेक्ट को हटा दिया जाता है (कहते हैं, आपकी बुलेट किसी ऑब्जेक्ट को हिट करती है और नष्ट हो जाती है)। मुख्य वस्तु सूची में स्मृति के उस स्थान पर मौजूद वस्तु को उसका संस्करण संख्या टकराया हुआ है, जो उसे (10,2) देता है। यदि आप एक बासी आईडी से फिर से (10,1) देखने की कोशिश करते हैं, तो अनुक्रमणिका 10 के माध्यम से वह वस्तु वापस आ जाती है, लेकिन यह देख सकते हैं कि संस्करण संख्या बदल गई है, इसलिए आईडी अब मान्य नहीं है।
यह पूरी तरह से सबसे तेज़ डेटा संरचना है जो आपके पास एक स्थिर आईडी के साथ हो सकती है जो वस्तुओं को स्मृति में स्थानांतरित करने की अनुमति देती है, जो डेटा स्थानीयता और कैश सुसंगतता के लिए महत्वपूर्ण है। यह संभव हैश तालिका के किसी भी कार्यान्वयन से तेज है; बहुत से कम से कम एक हैश की गणना करने के लिए एक हैश तालिका (एक टेबल लुकअप की तुलना में अधिक निर्देश) और फिर हैश चेन (या तो std के भयानक मामले में एक लिंक की गई सूची का पालन करना है: unordered_map, या एक खुली पता सूची किसी हैश तालिका का कोई भी बेवकूफ कार्यान्वयन नहीं), और फिर प्रत्येक कुंजी पर कोई तुलना नहीं करना पड़ता है (संस्करण टैग की जाँच से अधिक महंगा, लेकिन संभव कम महंगा है)। एक बहुत अच्छी हैश टेबल (एसटीएल के किसी भी कार्यान्वयन में कोई भी नहीं, क्योंकि एसटीएल एक हैश टेबल को अनिवार्य करता है जो गेम ऑब्जेक्ट सूची के बारे में आपके द्वारा गेम से अलग उपयोग के मामलों के लिए अनुकूलन करता है) एक अप्रत्यक्ष पर बचा सकता है,
आधार एल्गोरिथ्म में आप कर सकते हैं विभिन्न सुधार। उदाहरण के लिए, मुख्य ऑब्जेक्ट सूची के लिए std :: deque जैसी किसी चीज़ का उपयोग करना; अप्रत्यक्षता की एक अतिरिक्त परत, लेकिन स्लॉटमैप से आपके द्वारा प्राप्त किए गए किसी भी अस्थायी संकेत को अमान्य किए बिना वस्तुओं को पूरी सूची में डालने की अनुमति देता है।
आप ऑब्जेक्ट के अंदर इंडेक्स को स्टोर करने से भी बच सकते हैं, क्योंकि इंडेक्स को ऑब्जेक्ट की मेमोरी एड्रेस (यह - ऑब्जेक्ट्स) से गणना की जा सकती है, और इससे भी बेहतर केवल उस ऑब्जेक्ट को हटाते समय होता है जिस स्थिति में आपके पास ऑब्जेक्ट की आईडी (और इसलिए) सूचकांक) एक पैरामीटर के रूप में।
लिखने के लिए माफी; मुझे नहीं लगता कि यह सबसे स्पष्ट विवरण हो सकता है। यह देर हो चुकी है और मेरे पास कोड नमूनों की तुलना में अधिक समय खर्च किए बिना समझाना मुश्किल है।