मैं गुरुत्वाकर्षण कैसे लागू कर सकता हूं?


44

मैं गुरुत्वाकर्षण कैसे लागू कर सकता हूं? किसी विशेष भाषा के लिए नहीं, सिर्फ छद्म ...



2
इस सवाल पर स्वीकृत उत्तर आपको मदद करनी चाहिए: gamedev.stackexchange.com/questions/13178/…
Tetrad

जवाबों:


52

जैसा कि अन्य ने टिप्पणी में उल्लेख किया है, दसप के उत्तर में वर्णित मूल यूलर एकीकरण विधि कुछ समस्याओं से ग्रस्त है:

  • यहां तक ​​कि साधारण गति के लिए, जैसे निरंतर गुरुत्वाकर्षण के तहत बैलिस्टिक कूद, यह एक व्यवस्थित त्रुटि का परिचय देता है।

  • त्रुटि टाइमस्टेप पर निर्भर करती है, जिसका अर्थ है कि टाइमस्टेप बदलने से वस्तु प्रक्षेपवक्र व्यवस्थित तरीके से बदल जाते हैं जो खिलाड़ियों द्वारा देखे जा सकते हैं यदि खेल एक चर टाइमस्टेप का उपयोग करता है। यहां तक ​​कि एक निश्चित भौतिकी टाइमस्टेप वाले खेलों के लिए, विकास के दौरान टाइमस्टेप को बदलने से गेम भौतिकी पर विशेष रूप से प्रभाव पड़ सकता है जैसे कि किसी दिए गए बल के साथ लॉन्च की गई वस्तु उड़ जाएगी, संभवतः पहले से डिज़ाइन किए गए स्तरों को तोड़ना।

  • यह ऊर्जा का संरक्षण नहीं करता है, भले ही अंतर्निहित भौतिकी चाहिए। विशेष रूप से, वस्तुओं को स्थिर रूप से दोलन करना चाहिए (जैसे कि पेंडुलम, स्प्रिंग्स, परिक्रमा करने वाले ग्रह, आदि) पूरी तरह से ऊर्जा के जमा होने तक लगातार ऊर्जा जमा कर सकते हैं।

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

त्वरण = बल (समय, स्थिति) / द्रव्यमान;
समय + = टाइमस्टेप;
स्थिति + = टाइमस्टेप * वेग;
वेग + = टाइमस्टेप * त्वरण;

वेग वर्लेट विधि इसे इस तरह करती है:

त्वरण = बल (समय, स्थिति) / द्रव्यमान;
समय + = टाइमस्टेप;
स्थिति + = टाइमस्टेप * ( वेग + टाइमस्टेप * त्वरण / 2) ;
newAcceleration = बल (समय, स्थिति) / द्रव्यमान; 
वेग + = टाइमस्टेप * ( त्वरण + न्यू एक्सीलरेशन) / 2 ;

यदि आपके पास कई इंटरेक्टिव ऑब्जेक्ट हैं, तो आपको बलों को पुनर्गठित करने और वेगों को अपडेट करने से पहले अपने सभी पदों को अपडेट करना चाहिए । नए त्वरण (एस) को तब बचाया जा सकता है और अगले टाइमस्टेप पर स्थिति (एस) को अपडेट करने के लिए इस्तेमाल किया जा सकता है, कॉल करने की संख्या को घटाकर force()प्रति टाइमस्टेप प्रति एक (प्रति वस्तु) की तरह, यूलर विधि की तरह।

इसके अलावा, अगर त्वरण सामान्य रूप से स्थिर होता है (जैसे बैलिस्टिक जंपिंग के दौरान गुरुत्वाकर्षण), तो हम उपरोक्त को केवल सरल कर सकते हैं:

समय + = टाइमस्टेप;
स्थिति + = टाइमस्टेप * ( वेग + टाइमस्टेप * त्वरण / 2) ;
वेग + = टाइमस्टेप * त्वरण;

जहां मूल बोल्ड एकीकरण की तुलना में बोल्ड में अतिरिक्त शब्द एकमात्र परिवर्तन है।

यूलर एकीकरण की तुलना में, वेग वर्लेट और लीपफ्रॉग विधियों में कई अच्छे गुण हैं:

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

  • वे दूसरे क्रम के इंटीग्रेटर हैं, जिसका अर्थ है कि अलग-अलग त्वरण के साथ, औसत एकीकरण त्रुटि केवल टाइमपास के वर्ग के आनुपातिक है। यह सटीकता से समझौता किए बिना बड़े टाइमस्टेप के लिए अनुमति दे सकता है।

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

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


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

त्वरण = बल (समय, स्थिति, वेग) / द्रव्यमान;
समय + = टाइमस्टेप;
स्थिति + = टाइमस्टेप * ( वेग + टाइमस्टेप * त्वरण / 2) ;
वेग + = टाइमस्टेप * त्वरण;
newAcceleration = बल (समय, स्थिति, वेग) / द्रव्यमान; 
वेग + = टाइमस्टेप * (newAcceleration - त्वरण) / 2 ;

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

संपादन 2: एक बहुत ही समान एल्गोरिथ्म का वर्णन किया जाता है जैसे कि ग्रोट एंड वारेन ( जे। केम। फिजिक्स 1997) , हालांकि, लाइनों के बीच पढ़ने पर, ऐसा लगता है कि उन्होंने newAccelerationअनुमानित वेग का उपयोग करके गणना किए गए मूल्य को बचाकर अतिरिक्त गति के लिए कुछ सटीकता का बलिदान किया। और accelerationअगले टाइमस्टेप के लिए इसे फिर से उपयोग करना । वे एक पैरामीटर 0 ≤ λ introduce 1 भी पेश करते हैं जो accelerationप्रारंभिक वेग अनुमान में गुणा किया जाता है; किसी कारण से, वे λ = 0.5 की सलाह देते हैं , भले ही मेरे सभी परीक्षण उस λ का सुझाव देते हैं= 1 (जो प्रभावी रूप से मैं ऊपर उपयोग करता हूं) त्वरण के पुन: उपयोग के साथ या उसके बिना भी बेहतर या बेहतर काम करता है। शायद यह इस तथ्य के साथ कुछ करने के लिए मिला है कि उनकी ताकतों में एक स्टोकेस्टिक ब्राउनियन गति घटक शामिल है।


वेलोसिटी वेरलेट यह अच्छा है, लेकिन इसमें वेग से निर्भरता नहीं हो सकती है, इसलिए घर्षण को लागू नहीं किया जा सकता है। मुझे लगता है कि
रनगे

1
@PizziraniLeonardo: आप वेलोसिटी-निर्भर ताकतों के लिए भी वेग वर्लेट के ठीक एक प्रकार का (वेरिएंट) उपयोग कर सकते हैं; ऊपर मेरा संपादन देखें।
इल्मरी करोनन

1
साहित्य वेलोसिटी वर्लेट की इस व्याख्या को एक अलग नाम नहीं देता है। यह पूर्वसूचक -सुधारक रणनीति पर निर्भर करता है, जैसा कि इस पत्र में भी कहा गया है । fire.nist.gov/bfrlpubs/build99/PDF/b99014.pdf
टेओड्रन

3
@ Unit978: यह खेल पर निर्भर करता है, और विशेष रूप से इसे लागू करने वाले भौतिकी मॉडल पर। force(time, position, velocity)मेरा उत्तर ऊपर बस के लिए "बल पर एक वस्तु पर अभिनय आशुलिपि है में positionसे आगे बढ़ रही velocityपर time"। आमतौर पर, बल उन चीज़ों पर निर्भर करता है जैसे कि वस्तु फ़्रीफ़ॉल में है या ठोस सतह पर बैठी है, क्या आस-पास की कोई अन्य वस्तु उस पर एक बल लगा रही है, यह कितनी तेज़ी से एक सतह (घर्षण) और / या तरल के माध्यम से आगे बढ़ रहा है या गैस (ड्रैग), इत्यादि
इल्मरी करोनन

1
यह एक महान जवाब है, लेकिन यह निश्चित समय के कदम ( gafferongames.com/game-physics/fix-your-timestep ) के बारे में बात किए बिना अधूरा है । मैं एक अलग उत्तर जोड़ूंगा, लेकिन ज्यादातर लोग स्वीकार किए गए उत्तर पर रुकते हैं, खासकर जब इसमें इतने बड़े अंतर से सबसे अधिक वोट होते हैं, जैसा कि यहां है। मुझे लगता है कि इस एक को बढ़ाने के द्वारा समुदाय की बेहतर सेवा की जाती है।
जिब स्मार्ट

13

अपने खेल के हर अपडेट लूप, ऐसा करें:

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;

6
क्या मतलब? बस अपना गुरुत्वाकर्षण मूल्य चुनें और चूंकि यह आपके वेग को बदलता है, न केवल आपकी स्थिति को, यह स्वाभाविक दिखता है।
Pecant

1
मैं कभी भी गुरुत्वाकर्षण बंद करना पसंद करता हूं। मुझे लगता है कि गुरुत्वाकर्षण स्थिर होना चाहिए। जो चीज बदलनी चाहिए (इम्हो) वह कूदने की आपकी क्षमता है।
ultifinitus

2
यदि यह मदद करता है, तो इसे वास्तव में 'गुरुत्वाकर्षण' के बजाय 'गिरने' के रूप में सोचें। एक पूरे नियंत्रण के रूप में कार्य गुरुत्वाकर्षण के कारण वस्तु गिर रही है या नहीं । गुरुत्वाकर्षण ही मौजूद है कि [यहाँ गुरुत्वाकर्षण मूल्य डालें]। तो उस अर्थ में, गुरुत्वाकर्षण है निरंतर, तुम बस जब तक वस्तु हवाई है कुछ भी करने के लिए उसका उपयोग नहीं करते।
जेसन पाइनो

2
यह कोड फ्रेम-दर निर्भर है, जो बहुत अच्छा नहीं है, लेकिन यदि आपके पास लगातार अपडेट है तो आप हंस रहे हैं।
दस

1
-1, क्षमा करें। वेग और गुरुत्वाकर्षण, या स्थिति और वेग को जोड़ना, बस इसका कोई मतलब नहीं है। मैं समझता हूँ कि आप जो शॉर्टकट कर रहे हैं, लेकिन यह गलत है। मैं किसी भी छात्र या प्रशिक्षु या सहकर्मी को ऐसा करूँगा जो मुझे सबसे बड़े क्लूबट के साथ मिल सके। इकाइयों की संगति मायने रखती है।
सैम होसेवर

8

एक उचित फ्रेम-दर स्वतंत्र * न्यूटोनियन भौतिकी एकीकरण:

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 देखें ।


4
यूलर एकीकरण का उपयोग न करें। ग्लेन फिडलर का यह लेख देखें जो समस्याओं और समाधानों को मुझसे बेहतर बताता है। :)
मार्टिन सोज्का

1
मैं समझता हूं कि समय के साथ यूलर कैसे गलत है, लेकिन मुझे लगता है कि ऐसे परिदृश्य हैं जहां वास्तव में कोई फर्क नहीं पड़ता। जब तक नियम सभी के लिए संगत हैं, और यह "सही" लगता है, ठीक है। और अगर आप सिर्फ phyiscs के बारे में सीख रहे हैं, तो यह याद रखना और जोड़ना आसान है।
दस

... हालांकि अच्छा लिंक। ;)
दस

4
आप यूलर एकीकरण के साथ ज्यादातर मुद्दों को ठीक कर सकते हैं ( position += velocity * timestepऊपर केवल पुराने और नए वेगों का औसत है)। विशेष रूप से, यह इंटीग्रेटर सटीक परिणाम देता है यदि त्वरण स्थिर है, क्योंकि यह आमतौर पर गुरुत्वाकर्षण के लिए है। अलग-अलग त्वरण के तहत बेहतर सटीकता के लिए, आप वेग वर्लेट एकीकरण प्राप्त करने के लिए वेग अपडेट में एक समान सुधार जोड़ सकते हैं । position += (velocity - acceleration * timestep / 2) * timestepvelocity - acceleration * timestep / 2
इल्मरी करोनन

आपके तर्क समझ में आते हैं, और अशुद्धि अक्सर एक बड़ी बात नहीं होती है। लेकिन आपको यह दावा नहीं करना चाहिए कि यह एक "उचित फ्रेम-दर स्वतंत्र" एकीकरण है, क्योंकि यह सिर्फ (स्वतंत्र स्वतंत्र) नहीं है।
सैम होसेवर

3

यदि आप गुरुत्वाकर्षण को थोड़े बड़े पैमाने पर लागू करना चाहते हैं, तो आप प्रत्येक लूप में इस तरह की गणना का उपयोग कर सकते हैं:

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

हालांकि बड़े (गेलेक्टिक) पैमानों के लिए, गुरुत्वाकर्षण केवल "वास्तविक" गति बनाने के लिए पर्याप्त नहीं होगा। स्टार सिस्टम की बातचीत द्रव गतिशीलता के लिए नवियर-स्टोक्स समीकरणों द्वारा निर्देशित एक महत्वपूर्ण और बहुत ही दृश्यमान सीमा तक है, और आपको प्रकाश की परिमित गति - और इस प्रकार, गुरुत्वाकर्षण को भी ध्यान में रखना होगा।


1

इल्मरी करोनन द्वारा प्रदान किया गया कोड लगभग सही है, लेकिन थोड़ी गड़बड़ है। आप वास्तव में प्रति टिक 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;

चीयर्स '


मुझे लगता है कि आप गलत हैं, क्योंकि त्वरण वेग पर निर्भर करता है
सुपर

-4

पेकेंट के उत्तरदाता ने फ्रेम समय को नजरअंदाज कर दिया, और यह आपके भौतिकी के व्यवहार को समय-समय पर अलग बनाता है।

यदि आप एक बहुत ही सरल गेम बनाने जा रहे हैं, तो आप अपना छोटा भौतिकी इंजन बना सकते हैं - हर गतिमान वस्तु के लिए द्रव्यमान और सभी प्रकार के भौतिकी मापदंडों को असाइन करें, और टकराव का पता लगाएं, फिर उनकी स्थिति और वेग को हर फ्रेम में अपडेट करें। इस प्रगति में तेजी लाने के लिए, आपको टकराव की जाली को आसान बनाने, टकराव का पता लगाने के कॉल को कम करने आदि की आवश्यकता होती है। ज्यादातर मामलों में, यह एक दर्द है।

फिजिक्स, ओडीई और बुलेट जैसे भौतिकी इंजन का उपयोग करना बेहतर है। उनमें से कोई भी आपके लिए स्थिर और कुशल होगा।

http://www.nvidia.com/object/physx_new.html

http://bulletphysics.org/wordpress/


4
-1 अनसुनी प्रतिक्रिया जो सवाल का जवाब नहीं देती है।
doppelgreener

4
ठीक है, यदि आप इसे समय के लिए समायोजित करना चाहते हैं, तो आप अंतिम अद्यतन () से बीते हुए समय से वेग को माप सकते हैं।
पेकेंट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.