मैं गुरुत्वाकर्षण कैसे लागू कर सकता हूं? किसी विशेष भाषा के लिए नहीं, सिर्फ छद्म ...
मैं गुरुत्वाकर्षण कैसे लागू कर सकता हूं? किसी विशेष भाषा के लिए नहीं, सिर्फ छद्म ...
जवाबों:
जैसा कि अन्य ने टिप्पणी में उल्लेख किया है, दसप के उत्तर में वर्णित मूल यूलर एकीकरण विधि कुछ समस्याओं से ग्रस्त है:
यहां तक कि साधारण गति के लिए, जैसे निरंतर गुरुत्वाकर्षण के तहत बैलिस्टिक कूद, यह एक व्यवस्थित त्रुटि का परिचय देता है।
त्रुटि टाइमस्टेप पर निर्भर करती है, जिसका अर्थ है कि टाइमस्टेप बदलने से वस्तु प्रक्षेपवक्र व्यवस्थित तरीके से बदल जाते हैं जो खिलाड़ियों द्वारा देखे जा सकते हैं यदि खेल एक चर टाइमस्टेप का उपयोग करता है। यहां तक कि एक निश्चित भौतिकी टाइमस्टेप वाले खेलों के लिए, विकास के दौरान टाइमस्टेप को बदलने से गेम भौतिकी पर विशेष रूप से प्रभाव पड़ सकता है जैसे कि किसी दिए गए बल के साथ लॉन्च की गई वस्तु उड़ जाएगी, संभवतः पहले से डिज़ाइन किए गए स्तरों को तोड़ना।
यह ऊर्जा का संरक्षण नहीं करता है, भले ही अंतर्निहित भौतिकी चाहिए। विशेष रूप से, वस्तुओं को स्थिर रूप से दोलन करना चाहिए (जैसे कि पेंडुलम, स्प्रिंग्स, परिक्रमा करने वाले ग्रह, आदि) पूरी तरह से ऊर्जा के जमा होने तक लगातार ऊर्जा जमा कर सकते हैं।
सौभाग्य से, यूलर एकीकरण को किसी ऐसी चीज़ से बदलना मुश्किल नहीं है जो लगभग सरल है, फिर भी इनमें से कोई भी समस्या नहीं है - विशेष रूप से, एक दूसरे क्रम के सहानुभूति इंटीग्रेटर जैसे कि लीपफ्रॉग एकीकरण या निकटता से संबंधित वेग वर्लेट विधि । विशेष रूप से, जहां मूल यूलर एकीकरण वेग और स्थिति को अद्यतन करता है:
त्वरण = बल (समय, स्थिति) / द्रव्यमान; समय + = टाइमस्टेप; स्थिति + = टाइमस्टेप * वेग; वेग + = टाइमस्टेप * त्वरण;
वेग वर्लेट विधि इसे इस तरह करती है:
त्वरण = बल (समय, स्थिति) / द्रव्यमान; समय + = टाइमस्टेप; स्थिति + = टाइमस्टेप * ( वेग + टाइमस्टेप * त्वरण / 2) ; newAcceleration = बल (समय, स्थिति) / द्रव्यमान; वेग + = टाइमस्टेप * ( त्वरण + न्यू एक्सीलरेशन) / 2 ;
यदि आपके पास कई इंटरेक्टिव ऑब्जेक्ट हैं, तो आपको बलों को पुनर्गठित करने और वेगों को अपडेट करने से पहले अपने सभी पदों को अपडेट करना चाहिए । नए त्वरण (एस) को तब बचाया जा सकता है और अगले टाइमस्टेप पर स्थिति (एस) को अपडेट करने के लिए इस्तेमाल किया जा सकता है, कॉल करने की संख्या को घटाकर force()
प्रति टाइमस्टेप प्रति एक (प्रति वस्तु) की तरह, यूलर विधि की तरह।
इसके अलावा, अगर त्वरण सामान्य रूप से स्थिर होता है (जैसे बैलिस्टिक जंपिंग के दौरान गुरुत्वाकर्षण), तो हम उपरोक्त को केवल सरल कर सकते हैं:
समय + = टाइमस्टेप; स्थिति + = टाइमस्टेप * ( वेग + टाइमस्टेप * त्वरण / 2) ; वेग + = टाइमस्टेप * त्वरण;
जहां मूल बोल्ड एकीकरण की तुलना में बोल्ड में अतिरिक्त शब्द एकमात्र परिवर्तन है।
यूलर एकीकरण की तुलना में, वेग वर्लेट और लीपफ्रॉग विधियों में कई अच्छे गुण हैं:
निरंतर त्वरण के लिए, वे सटीक परिणाम देते हैं (फ़्लोटिंग पॉइंट राउंडऑफ़ त्रुटियों तक, वैसे भी), जिसका अर्थ है कि बैलेस्टिक जंप ट्रैजेटरीज टाइमस्टेप बदलने पर भी समान रहती हैं।
वे दूसरे क्रम के इंटीग्रेटर हैं, जिसका अर्थ है कि अलग-अलग त्वरण के साथ, औसत एकीकरण त्रुटि केवल टाइमपास के वर्ग के आनुपातिक है। यह सटीकता से समझौता किए बिना बड़े टाइमस्टेप के लिए अनुमति दे सकता है।
वे सहानुभूतिपूर्ण हैं , जिसका अर्थ है कि वे ऊर्जा का संरक्षण करते हैं यदि अंतर्निहित भौतिकी करते हैं (कम से कम जब तक टाइमस्टेप स्थिर है)। विशेष रूप से, इसका मतलब है कि आप ग्रहों की तरह चीजें नहीं पाएंगे जो अनायास उनकी कक्षाओं से बाहर उड़ रहे हैं, या एक दूसरे से जुड़ी हुई वस्तुएं धीरे-धीरे अधिक से अधिक घूमती हैं जब तक कि पूरी चीज उड़ नहीं जाती।
फिर भी वेग वर्लेट / लीपफ्रॉग पद्धति लगभग मूल यूलर एकीकरण की तरह सरल और तेज है, और निश्चित रूप से चौथे क्रम के रन-कुट्टा एकीकरण जैसे विकल्पों की तुलना में बहुत सरल है (जो, जबकि आम तौर पर बहुत अच्छा इंटीग्रेटर होता है, सहानुभूति की संपत्ति का अभाव होता है और चार मूल्यांकन की आवश्यकता होती है के force()
समय प्रत्येक चरण में समारोह)। इस प्रकार, मैं किसी को भी किसी भी प्रकार के गेम भौतिकी कोड लिखने की दृढ़ता से सलाह दूंगा, भले ही यह एक मंच से दूसरे में कूदने जितना सरल हो।
संपादित करें: जबकि वेग की औपचारिक व्युत्पत्ति वर्लेट विधि केवल तभी मान्य होती है जब सेनाएं वेग से स्वतंत्र होती हैं, व्यवहार में आप इसे वेग-निर्भर बलों जैसे कि द्रव खींचें के साथ भी ठीक उपयोग कर सकते हैं । सर्वोत्तम परिणामों के लिए, आपको force()
इस तरह की दूसरी कॉल के लिए नए वेग का अनुमान लगाने के लिए प्रारंभिक त्वरण मूल्य का उपयोग करना चाहिए :
त्वरण = बल (समय, स्थिति, वेग) / द्रव्यमान; समय + = टाइमस्टेप; स्थिति + = टाइमस्टेप * ( वेग + टाइमस्टेप * त्वरण / 2) ; वेग + = टाइमस्टेप * त्वरण; newAcceleration = बल (समय, स्थिति, वेग) / द्रव्यमान; वेग + = टाइमस्टेप * (newAcceleration - त्वरण) / 2 ;
मुझे यकीन नहीं है कि अगर वेग वेरलेट विधि के इस विशेष संस्करण का एक विशिष्ट नाम है, लेकिन मैंने इसका परीक्षण किया है और यह बहुत अच्छी तरह से काम करता है। यह फाउट-ऑर्डर रन-कुट्टा (जैसा कि एक दूसरे-ऑर्डर विधि से उम्मीद होगी) के रूप में बिल्कुल सटीक नहीं है, लेकिन यह मध्यवर्ती वेग अनुमान के बिना यूलर या भोले वेग वर्लेट की तुलना में बहुत बेहतर है, और यह अभी भी सामान्य की सहानुभूति संपत्ति को बरकरार रखता है रूढ़िवादी, गैर-वेग-निर्भर बलों के लिए वेग वेरलेट।
संपादन 2: एक बहुत ही समान एल्गोरिथ्म का वर्णन किया जाता है जैसे कि ग्रोट एंड वारेन ( जे। केम। फिजिक्स 1997) , हालांकि, लाइनों के बीच पढ़ने पर, ऐसा लगता है कि उन्होंने newAcceleration
अनुमानित वेग का उपयोग करके गणना किए गए मूल्य को बचाकर अतिरिक्त गति के लिए कुछ सटीकता का बलिदान किया। और acceleration
अगले टाइमस्टेप के लिए इसे फिर से उपयोग करना । वे एक पैरामीटर 0 ≤ λ introduce 1 भी पेश करते हैं जो acceleration
प्रारंभिक वेग अनुमान में गुणा किया जाता है; किसी कारण से, वे λ = 0.5 की सलाह देते हैं , भले ही मेरे सभी परीक्षण उस λ का सुझाव देते हैं= 1 (जो प्रभावी रूप से मैं ऊपर उपयोग करता हूं) त्वरण के पुन: उपयोग के साथ या उसके बिना भी बेहतर या बेहतर काम करता है। शायद यह इस तथ्य के साथ कुछ करने के लिए मिला है कि उनकी ताकतों में एक स्टोकेस्टिक ब्राउनियन गति घटक शामिल है।
force(time, position, velocity)
मेरा उत्तर ऊपर बस के लिए "बल पर एक वस्तु पर अभिनय आशुलिपि है में position
से आगे बढ़ रही velocity
पर time
"। आमतौर पर, बल उन चीज़ों पर निर्भर करता है जैसे कि वस्तु फ़्रीफ़ॉल में है या ठोस सतह पर बैठी है, क्या आस-पास की कोई अन्य वस्तु उस पर एक बल लगा रही है, यह कितनी तेज़ी से एक सतह (घर्षण) और / या तरल के माध्यम से आगे बढ़ रहा है या गैस (ड्रैग), इत्यादि
अपने खेल के हर अपडेट लूप, ऐसा करें:
if (collidingBelow())
gravity = 0;
else gravity = [insert gravity value here];
velocity.y += gravity;
उदाहरण के लिए, एक प्लेटफ़ॉर्मर में, जब आप एक बार कूदते हैं, तो गुरुत्वाकर्षण सक्षम होता है (टकराता हुआ बेलबो आपको बताता है कि आपके ठीक नीचे जमीन है या नहीं) और एक बार जब आप मैदान मारते हैं तो यह अक्षम हो जाएगा।
इसके अलावा, छलांग लगाने के लिए, फिर यह करें:
if (pressingJumpButton() && collidingBelow())
velocity.y = [insert jump speed here]; // the jump speed should be negative
और बहुत स्पष्ट रूप से, अपडेट लूप में आपको अपनी स्थिति को भी अपडेट करना होगा:
position += velocity;
एक उचित फ्रेम-दर स्वतंत्र * न्यूटोनियन भौतिकी एकीकरण:
Vector forces = 0.0f;
// gravity
forces += down * m_gravityConstant; // 9.8m/s/s on earth
// left/right movement
forces += right * m_movementConstant * controlInput; // where input is scaled -1..1
// add other forces in for taste - usual suspects include air resistence
// proportional to the square of velocity, against the direction of movement.
// this has the effect of capping max speed.
Vector acceleration = forces / m_massConstant;
m_velocity += acceleration * timeStep;
m_position += velocity * timeStep;
जब तक यह सही न लगे, ट्वीक ग्रेविटीस्टैंट, मूवमेंट कंसेंट और मासकॉनस्टैंट। यह एक सहज बात है और बहुत अच्छा महसूस करने में थोड़ा समय लग सकता है।
नए गेमप्ले को जोड़ने के लिए सदिश बलों को विस्तारित करना आसान है - उदाहरण के लिए किसी भी पास के विस्फोट से दूर या ब्लैक होल की ओर एक बल जोड़ें।
* संपादित करें: ये परिणाम समय के साथ गलत होंगे, लेकिन आपकी निष्ठा या योग्यता के लिए "काफी अच्छे" हो सकते हैं। अधिक जानकारी के लिए इस लिंक http://lol.zoy.org/blog/2011/12/14/understanding-motion-in-games देखें ।
position += velocity * timestep
ऊपर केवल पुराने और नए वेगों का औसत है)। विशेष रूप से, यह इंटीग्रेटर सटीक परिणाम देता है यदि त्वरण स्थिर है, क्योंकि यह आमतौर पर गुरुत्वाकर्षण के लिए है। अलग-अलग त्वरण के तहत बेहतर सटीकता के लिए, आप वेग वर्लेट एकीकरण प्राप्त करने के लिए वेग अपडेट में एक समान सुधार जोड़ सकते हैं । position += (velocity - acceleration * timestep / 2) * timestep
velocity - acceleration * timestep / 2
यदि आप गुरुत्वाकर्षण को थोड़े बड़े पैमाने पर लागू करना चाहते हैं, तो आप प्रत्येक लूप में इस तरह की गणना का उपयोग कर सकते हैं:
for each object in the scene
for each other_object in the scene not equal to object
if object.mass * other_object.mass / object.distanceSquaredBetweenCenterOfMasses(other_object) < epsilon
abort the calculation for this pair
if object.mass is much, much bigger than other_object.mass
abort the calculation for this pair
force = gravitational_constant
* object.mass * other_object.mass
/ object.distanceSquaredBetweenCenterOfMasses(other_object)
object.addForceAtCenterOfMass(force * object.normalizedDirectionalVectorTo(other_object))
end for loop
end for loop
हालांकि बड़े (गेलेक्टिक) पैमानों के लिए, गुरुत्वाकर्षण केवल "वास्तविक" गति बनाने के लिए पर्याप्त नहीं होगा। स्टार सिस्टम की बातचीत द्रव गतिशीलता के लिए नवियर-स्टोक्स समीकरणों द्वारा निर्देशित एक महत्वपूर्ण और बहुत ही दृश्यमान सीमा तक है, और आपको प्रकाश की परिमित गति - और इस प्रकार, गुरुत्वाकर्षण को भी ध्यान में रखना होगा।
इल्मरी करोनन द्वारा प्रदान किया गया कोड लगभग सही है, लेकिन थोड़ी गड़बड़ है। आप वास्तव में प्रति टिक 2 बार त्वरण की गणना करते हैं, यह पाठ्यपुस्तक समीकरणों का पालन नहीं करता है।
acceleration = force(time, position) / mass; // Here
time += timestep;
position += timestep * (velocity + timestep * acceleration / 2);
newAcceleration = force(time, position) / mass;
velocity += timestep * (acceleration + newAcceleration) / 2;
निम्न मॉड सही है:
time += timestep;
position += timestep * (velocity + timestep * acceleration / 2);
oldAcceletation = acceleration; // Store it
acceleration = force(time, position) / mass;
velocity += timestep * (acceleration + oldAcceleration) / 2;
चीयर्स '
पेकेंट के उत्तरदाता ने फ्रेम समय को नजरअंदाज कर दिया, और यह आपके भौतिकी के व्यवहार को समय-समय पर अलग बनाता है।
यदि आप एक बहुत ही सरल गेम बनाने जा रहे हैं, तो आप अपना छोटा भौतिकी इंजन बना सकते हैं - हर गतिमान वस्तु के लिए द्रव्यमान और सभी प्रकार के भौतिकी मापदंडों को असाइन करें, और टकराव का पता लगाएं, फिर उनकी स्थिति और वेग को हर फ्रेम में अपडेट करें। इस प्रगति में तेजी लाने के लिए, आपको टकराव की जाली को आसान बनाने, टकराव का पता लगाने के कॉल को कम करने आदि की आवश्यकता होती है। ज्यादातर मामलों में, यह एक दर्द है।
फिजिक्स, ओडीई और बुलेट जैसे भौतिकी इंजन का उपयोग करना बेहतर है। उनमें से कोई भी आपके लिए स्थिर और कुशल होगा।