आप अपडेट (लॉजिक टिक) को अलग करना चाहते हैं और टिक को रेंडर (रेंडर करना) करते हैं।
आपके अपडेट से दुनिया की सभी वस्तुओं की स्थिति तैयार की जाएगी।
मैं यहां दो अलग-अलग संभावनाओं को कवर करूंगा, एक जो आपने अनुरोध किया था, एक्सट्रपलेशन, और एक अन्य विधि, प्रक्षेप।
1।
एक्सट्रैपलेशन वह जगह है जहां हम अगले फ्रेम में ऑब्जेक्ट की (अनुमानित) स्थिति की गणना करेंगे, और फिर वर्तमान ऑब्जेक्ट की स्थिति के बीच इंटरपोलेट करेंगे और वह स्थिति जो ऑब्जेक्ट अगले फ्रेम में होगी।
ऐसा करने के लिए, खींची जाने वाली प्रत्येक वस्तु में एक संबद्ध velocity
और होना चाहिए position
। उस स्थिति को खोजने के लिए कि ऑब्जेक्ट अगले फ्रेम पर होगा, हम बस velocity * draw_timestep
ऑब्जेक्ट की वर्तमान स्थिति में जोड़ते हैं, अगले फ्रेम की अनुमानित स्थिति का पता लगाने के लिए। draw_timestep
पिछली रेंडर टिक (उर्फ पिछले ड्रॉ कॉल) के बाद से जितना समय बीत चुका है, उतनी बार है।
यदि आप इसे इस पर छोड़ देते हैं, तो आप पाएंगे कि ऑब्जेक्ट "झिलमिलाहट" जब उनकी अनुमानित स्थिति अगले फ्रेम में वास्तविक स्थिति से मेल नहीं खाती थी। चंचलता को दूर करने के लिए, आप पूर्व- निर्धारित स्थिति और प्रत्येक ड्रॉ कदम पर नई अनुमानित स्थिति के बीच पूर्वानुमेय स्थिति, और lerp को संग्रहीत कर सकते हैं, पिछले अद्यतन के बाद से lerp फ़ैक्टर के रूप में टिक किए गए समय का उपयोग करते हुए। यह तब भी खराब व्यवहार का परिणाम होगा जब तेजी से आगे बढ़ने वाली वस्तुएं अचानक स्थान बदलती हैं, और आप उस विशेष मामले को संभालना चाह सकते हैं। इस पैराग्राफ में कहा गया सब कुछ वे कारण हैं जिनके कारण आप एक्सट्रपलेशन का उपयोग नहीं करना चाहते हैं।
2।
इंटरपोलेशन वह जगह है जहां हम अंतिम दो अपडेट की स्थिति को स्टोर करते हैं, और उनके बीच इंटरपोल करते हैं जो वर्तमान में पिछले अपडेट के बाद से गुजरे हैं। इस सेटअप में, प्रत्येक ऑब्जेक्ट में एक संबद्ध position
और होना चाहिए previous_position
। इस स्थिति में, हमारा ड्राइंग वर्तमान गेमस्टेट के पीछे सबसे खराब एक अपडेट टिक का प्रतिनिधित्व करेगा, और सबसे अच्छा, ठीक उसी स्थिति में जो वर्तमान अपडेट टिक के रूप में होगा।
मेरी राय में, आप शायद इंटरपोलेशन चाहते हैं जैसा कि मैंने इसे वर्णित किया है, क्योंकि इसे लागू करने के लिए दो का आसान है, और आपके वर्तमान अद्यतन स्थिति के पीछे एक दूसरे (जैसे 1/60 सेकंड) के एक छोटे से अंश को खींचना ठीक है।
संपादित करें:
यदि आपको एक कार्यान्वयन करने की अनुमति देने के लिए उपरोक्त पर्याप्त नहीं है, तो यहां एक उदाहरण है कि मैंने जो इंटरपोलेशन विधि बताई है उसे कैसे करें। मैं एक्सट्रपलेशन को कवर नहीं करूंगा, क्योंकि मैं किसी भी वास्तविक दुनिया के परिदृश्य के बारे में नहीं सोच सकता जिसमें आपको इसे पसंद करना चाहिए।
जब आप एक आकर्षित करने योग्य वस्तु बनाते हैं, तो वह खींची जाने वाली आवश्यक संपत्तियों को संग्रहीत करेगा (यानी, इसे खींचने के लिए आवश्यक राज्य जानकारी)।
इस उदाहरण के लिए, हम स्थिति और रोटेशन को स्टोर करेंगे। आप रंग या बनावट समन्वय स्थिति (जैसे कि एक बनावट स्क्रॉल) जैसे अन्य गुणों को संग्रहीत करना चाहते हैं।
रेंडर थ्रेड को आरेखित करते समय डेटा को संशोधित करने से रोकने के लिए, (रेंडर थ्रेड ड्रॉ करते समय एक वस्तु का स्थान बदल जाता है, लेकिन अन्य सभी अभी तक अपडेट नहीं किए गए हैं), हमें कुछ प्रकार के डबल बफ़रिंग को लागू करने की आवश्यकता है।
एक वस्तु इसकी दो प्रतियाँ संग्रहीत करती है previous_state
। मैं उन्हें एक सरणी में डाल दिया जाएगा और के रूप में उन्हें previous_state[0]
और previous_state[1]
। इसी तरह इसकी दो प्रतियाँ चाहिए current_state
।
डबल बफर की किस कॉपी का उपयोग किया जाता है, इस पर नज़र रखने के लिए हम एक वैरिएबल स्टोर करते हैं state_index
, जो अपडेट और ड्रा थ्रेड दोनों के लिए उपलब्ध है।
अपडेट थ्रेड पहले किसी ऑब्जेक्ट के सभी गुणों की गणना करता है, यह स्वयं का डेटा (कोई भी डेटा संरचनाएं जो आप चाहते हैं) का उपयोग कर रहा है। फिर, यह प्रतियां current_state[state_index]
करने के लिए previous_state[state_index]
प्रतियां, और ड्राइंग, के लिए नए डेटा प्रासंगिक position
और rotation
में current_state[state_index]
। फिर यह state_index = 1 - state_index
डबल बफर की वर्तमान में इस्तेमाल की गई कॉपी को फ्लिप करने के लिए करता है ।
ऊपर दिए गए पैराग्राफ में सब कुछ एक लॉक आउट के साथ किया जाना है current_state
। अद्यतन और ड्रा थ्रेड्स दोनों इस लॉक को बाहर निकालते हैं। लॉक केवल राज्य की जानकारी की प्रतिलिपि की अवधि के लिए निकाला जाता है, जो तेज है।
रेंडर थ्रेड में, आप तब स्थिति और रोटेशन पर एक रेखीय प्रक्षेप करते हैं जैसे:
current_position = Lerp(previous_state[state_index].position, current_state[state_index].position, elapsed/update_tick_length)
कहाँ elapsed
समय है कि धागा प्रस्तुत करना में बीत चुका है, अंतिम अद्यतन टिक के बाद से की राशि है, और update_tick_length
है कि अपने तय अद्यतन दर टिक प्रति लेता है (उदाहरण के लिए 20fps अपडेट पर, समय की राशि है update_tick_length = 0.05
)।
यदि आपको नहीं पता है कि Lerp
उपरोक्त कार्य क्या है, तो इस विषय पर विकिपीडिया के लेख को चेकआउट करें: लीनियर इंटरपोलेशन । हालाँकि, यदि आप नहीं जानते हैं कि लेरपिंग क्या है, तो आप शायद इंटरपोलेटेड ड्राइंग के साथ अपडाउन्ड अपडेट / ड्राइंग को लागू करने के लिए तैयार नहीं हैं।