किसी वस्तु को दूसरी वस्तु की परिधि के साथ कैसे स्थानांतरित किया जाए?


11

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

तो यहाँ गणितीय समस्या यह है कि कैसे प्राप्त करें (aX, aY) और (bX, bY) स्थिति, जब मैं केंद्र (cX, cY), वस्तु स्थिति (oX, oY) को जानता हूं और स्थानांतरित करने के लिए आवश्यक दूरी (d)

यहाँ छवि विवरण दर्ज करें


1
है dएक रेखीय दूरी या यह एक चाप है?
MichaelHouse

यह पिक्सल में एक रैखिक दूरी है
लुमिस

क्या आप उन सभी से परिचित हैं जो वैक्टर हैं और उन पर बुनियादी संचालन क्या है?
पैट्रिक ह्यूजेस

@ पैट्रिक नहीं, मुझे लगता है कि मुझे वैक्टर पर एक कोर्स करना होगा। चूँकि यह फ़्रेम फ़्रेम द्वारा एनीमेशन है इसलिए कोड तेज़ और अनुकूलित होना चाहिए।
लूमिस

जवाबों:


8

( गुफा: मैं यहां दो सन्निकटन का उपयोग कर रहा हूं: पहला d एक चाप की लंबाई के रूप में लेता है, और दूसरा इसे एक ऑर्थोगोनल लंबाई के रूप में लेता है। ये दोनों सन्दर्भ d के अपेक्षाकृत छोटे मानों के लिए अच्छे होने चाहिए, लेकिन वे पूर्ण नहीं होते हैं टिप्पणियों में स्पष्ट किया गया सटीक प्रश्न।)

इस पर गणित, सौभाग्य से, अपेक्षाकृत सरल है। सबसे पहले, हम अपने केंद्र की स्थिति से हमारे वर्तमान स्थिति के सापेक्ष वेक्टर पा सकते हैं:

deltaX = oX-cX;
deltaY = oY-cY;

और एक बार जब हमारे पास यह सापेक्ष वेक्टर होता है, तो हम उस सर्कल की त्रिज्या जान सकते हैं जिस पर हम काम कर रहे हैं:

radius = sqrt(deltaX*deltaX+deltaY*deltaY);

क्या अधिक है, हमारे सापेक्ष वेक्टर से हम सटीक कोण प्राप्त कर सकते हैं जो cX से oX तक की रेखा पर है:

curTheta = atan2(deltaX, deltaY);

अब चीजें थोड़ी पेचीदा हो जाती हैं। सबसे पहले, यह समझें कि एक वृत्त की परिधि - अर्थात्, 2π के कोणीय माप के साथ एक चाप की 'चाप लंबाई' - 2πr है। सामान्य तौर पर, त्रिज्या r के एक वृत्त के साथ, के कोणीय माप के साथ एक चाप की चाप लंबाई सिर्फ θr है। यदि हम आपके आरेख में d का उपयोग आर्क लंबाई के रूप में कर रहे थे, और चूंकि हम त्रिज्या को जानते हैं, तो हम केवल विभाजन करके हमें नई स्थिति में लाने के लिए थीटा में परिवर्तन पा सकते हैं:

deltaTheta = d/radius; // treats d as a distance along the arc

उस मामले के लिए जहां घ को एक रैखिक दूरी की आवश्यकता होती है, चीजें थोड़ी अधिक जटिल होती हैं, लेकिन सौभाग्य से ज्यादा नहीं। वहाँ, d एक आइसोसेलेज़ त्रिकोण का एक पक्ष है, जिसके अन्य दो किनारे सर्कल की त्रिज्या (क्रमशः cX / cY से oX / oY और aX / aY तक) हैं, और इस आइसोसेल त्रिकोण को द्विभाजित करने से हमें दो सही त्रिकोण मिलते हैं, जिनमें से प्रत्येक एक पक्ष के रूप में d / 2 है और कर्ण के रूप में त्रिज्या है; इसका मतलब यह है कि हमारे आधे कोण की साइन (d / 2) / त्रिज्या है, और इसलिए पूर्ण कोण सिर्फ दो बार है:

deltaTheta = 2*asin(d/(2*radius)); // treats d as a linear distance

ध्यान दें कि यदि आपने इस सूत्र से असिन को बाहर निकाल लिया और 2s को रद्द कर दिया, तो यह अंतिम सूत्र के समान होगा; यह वही है जो यह कह रहा है कि पाप (x) x के छोटे मानों के लिए लगभग x है, जिसे जानने के लिए एक उपयोगी सन्निकटन है।

अब हम केवल जोड़ या घटाकर नया कोण पा सकते हैं:

newTheta = curTheta+deltaTheta; // This will take you to aX, aY. For bX/bY, use curTheta-deltaTheta

एक बार जब हमारे पास नया कोण होता है, तो हम अपने अपडेट किए गए सापेक्ष वेक्टर को खोजने के लिए कुछ मूल ट्रिगर का उपयोग कर सकते हैं:

newDeltaX = radius*cos(newTheta);
newDeltaY = radius*sin(newTheta);

और हमारे केंद्र की स्थिति और हमारे सापेक्ष वेक्टर से हम (अंततः) लक्ष्य बिंदु को पा सकते हैं:

aX = cX+newDeltaX;
aY = cY+newDeltaY;

अब, इस सब के साथ, कुछ बड़े चेतावनी के बारे में पता होना चाहिए। एक के लिए, आप देखेंगे कि यह गणित ज्यादातर फ्लोटिंग-पॉइंट है, और वास्तव में यह लगभग होना ही है; लूप में अद्यतन करने के लिए इस पद्धति का उपयोग करने की कोशिश करना और हर चरण में पूर्णांक मानों को वापस करना, आपके सर्कल को बंद नहीं करने से सब कुछ कर सकता है (या तो लूप के चारों ओर जाने पर हर बार आवक या जावक को सर्पिल करना) इसे पहले से शुरू नहीं करना। जगह! (यदि आपका d बहुत छोटा है, तो आपको पता चल सकता है कि aX / aY या bX / bY के गोल संस्करण ठीक उसी जगह हैं, जहां आपका प्रारंभ स्थान oX / oY था।) दूसरे के लिए, यह बहुत महंगा है, विशेष रूप से इसके लिए कोशिश कर रहा है। करना; सामान्य तौर पर, यदि आप जानते हैं कि आपका चरित्र एक गोलाकार चाप में जा रहा है, तो आपको पूरे चाप को पहले से योजनाबद्ध करना चाहिए और नहींइसे फ्रेम से फ्रेम की तरह इस तरह से टिक कर दें, क्योंकि यहां सबसे महंगी गणना लागतों में कटौती करने के लिए फ्रंट लोड की जा सकती है। लागतों को वापस ट्रिम करने का एक और अच्छा तरीका है, अगर आप वास्तव में इस तरह से वृद्धि करना चाहते हैं, तो पहली जगह में ट्रिगर का उपयोग नहीं करना है; यदि d छोटा है और आपको इसके ठीक-ठीक होने की जरूरत नहीं है , लेकिन बहुत करीब है, तो आप 'd' को dx से oX / oY तक लम्बाई के वेक्टर में जोड़कर 'ट्रिक' कर सकते हैं, अपने केंद्र की ओर वेक्टर को orthogonal (ध्यान दें कि a) वेक्टर ऑर्थोगोनल टू (dX, dY) (-dY, dX)) द्वारा दिया गया है, और फिर इसे सही लंबाई तक सिकोड़ें। मैं इस कोड को बहुत चरण-दर-चरण नहीं समझाऊंगा, लेकिन उम्मीद है कि यह समझ में आएगा कि आपने अब तक क्या देखा है। ध्यान दें कि हम अंतिम चरण में नए डेल्टा वेक्टर को 'सिकोड़ें'

deltaX = oX-cX; deltaY = oY-cY;
radius = sqrt(deltaX*deltaX+deltaY*deltaY);
orthoX = -deltaY*d/radius;
orthoY = deltaX*d/radius;
newDeltaX = deltaX+orthoX; newDeltaY = deltaY+orthoY;
newLength = sqrt(newDeltaX*newDeltaX+newDeltaY*newDeltaY);
aX = cX+newDeltaX*radius/newLength; aY = cY+newDeltaY*radius/newLength;

1
स्टीवन मुझे लगता है कि मैं पहले अनुमान लगाने की कोशिश करने जा रहा हूं क्योंकि यह सिर्फ एक खेल है जहां सटीक से प्राकृतिक और दिलचस्प महसूस करना अधिक महत्वपूर्ण है। गति भी मायने रखती है। इस लंबे और अच्छे ट्यूटोरियल के लिए धन्यवाद!
लूमिस

वाह, स्टीवन अपने सन्निकटन एक सपने की तरह काम कर रहा है! क्या आप मुझे बता सकते हैं कि bX, bY पाने के लिए अपने कोड को कैसे बदलें। मैं अभी तक आपकी ओर्थोगोनल अवधारणा पर स्पष्ट नहीं हूं ...
लुमिस

2
ज़रूर! आप वास्तव में कुछ बिंदु पर वेक्टर गणित को समझना चाहते हैं, और एक बार जब आप मुझे संदेह करते हैं कि यह दूसरी प्रकृति होगी; bX / bY प्राप्त करने के लिए आपको बस (विशेष रूप से) ऑर्थोगोनल वेक्टर को जोड़ने के बजाय, इसे दूसरे शब्दों में 'इधर-उधर' जाना होगा। उपरोक्त कोड के संदर्भ में, यह 'newDeltaX = deltaX-orthoX' होगा; newDeltaY = deltaY-orthoY? ', उसके बाद newLength की गणना और फिर' bX = cX + newDeltaX त्रिज्या / newLength; bY = cY + newDeltaY त्रिज्या / newLength; '।
स्टीवन स्टैडनिक जू

असल में, वह कोड bX / bY की दिशा में newDeltaX / newDeltaY को इंगित करेगा (इसके बजाय aX / aY की दिशा में), फिर फिट करने के लिए ट्रिम करें और केंद्र में जोड़ें जैसे ही आपको aX / aY मिलेगा।
स्टीवन स्टैडनिक

9

आपके पास पहले से मौजूद दो पक्षों (एक तरफ 'c' से 'o' तक, दूसरा 'o' से 'a' तक) का उपयोग करते हुए एक त्रिकोण बनाएँ, और तीसरा पक्ष 'a' से 'c' तक जाता है। आप नहीं जानते कि 'a' अभी कहां है, बस कल्पना कीजिए कि अभी के लिए एक बिंदु है। आपको उस कोण के कोण की गणना करने के लिए त्रिकोणमिति की आवश्यकता होगी जो कि पक्ष 'd' के विपरीत हो। आपके पास पक्षों की लंबाई c <-> o और c <-> a है, क्योंकि वे दोनों वृत्त की त्रिज्या हैं।

अब जब आपके पास इस त्रिभुज के तीन किनारों की लंबाई है जिसे आप अभी तक नहीं देख सकते हैं, तो आप उस कोण को निर्धारित कर सकते हैं जो त्रिकोण के 'डी' पक्ष के विपरीत है। यहां आपको जरूरत है तो SSS (साइड-साइड-साइड) फॉर्मूला: http://www.teacherschoice.com.au/maths_library/trigonometry/solve_trig_sss.htm

SSS सूत्र का उपयोग करके आपके पास कोण है (जिसे हम 'j' कहेंगे) जो कि 'd' के विपरीत है। तो, अब हम गणना कर सकते हैं (aX, aY)।

// This is the angle from 'c' to 'o'
float angle = Math.atan2(oY - cY, oX - cX)

// Add the angle we calculated earlier.
angle += j;

Vector2 a = new Vector2( radius * Math.cos(angle), radius * Math.sin(angle) );

सुनिश्चित करें कि आप जिन कोणों की गणना कर रहे हैं, वे हमेशा रेडियन में हैं।

यदि आपको सर्कल के त्रिज्या की गणना करने की आवश्यकता है, तो आप वेक्टर घटाव का उपयोग कर सकते हैं, बिंदु 'ओ' से बिंदु 'ग' घटा सकते हैं, फिर परिणामी वेक्टर की लंबाई प्राप्त कर सकते हैं।

float lengthSquared = ( inVect.x * inVect.x
                      + inVect.y * inVect.y
                      + inVect.z * inVect.z );

float radius = Math.sqrt(lengthSquared);

ऐसा कुछ करना चाहिए, मुझे विश्वास है। मुझे जावा पता नहीं है, इसलिए मैंने सटीक सिंटैक्स पर अनुमान लगाया।

यहां उपयोगकर्ता द्वारा दी गई छवि Byte56बताती है कि यह त्रिभुज कैसा दिख सकता है: काओ त्रिकोण


1
मैं एक जवाब दे रहा था, लेकिन यह बात है। आप छवि मैं :) बनाया का उपयोग करने का स्वागत करते i.imgur.com/UUBgM.png
MichaelHouse

@ बाइट 56: धन्यवाद, मेरे पास वर्णन करने के लिए कोई छवि संपादक नहीं था।
निक फोस्टर

ध्यान दें कि त्रिज्या की गणना भी की जानी है; पूर्ण SSS गणना की तुलना में j होने के और अधिक सरल तरीके होने चाहिए, क्योंकि हमारे पास एक आइसोकेलेस त्रिकोण है।)
स्टीवन स्टैडनिक

हाँ, यह सरल लगता है, मुझे भी! Android में वेक्टर 2 नहीं है, इसलिए मुझे लगता है कि मैं केवल अलग-अलग मूल्यों का उपयोग कर सकता हूं। Intrestingly मुझे यहां Android के लिए मैन्युअल रूप से वेक्टर 2 वर्ग मिला: code.google.com/p/beginning-android-games-2/source/browse/trunk/…
Lumis

(मैंने सही रैखिक दूरी को खोजने के लिए अपना स्वयं का उत्तर दिया है - डेल्टा की दूसरी गणना - वहाँ 2 * असिन (डी / (2 * त्रिज्या)) के रूप में, यह है कि आप यहां जे कैसे पाएंगे।)
स्टीवन स्टैडनिकॉन

3

Obj1 को घुमाने के लिए obj1 के आस-पास घुमाएँ शायद कोशिश करें:

float angle = 0; //init angle

//call in an update
obj2.x = (obj1.x -= r*cos(angle));
obj2.y = (obj1.y += r*sin(angle));
angle-=0.5;

यह नहीं दिखाता है कि पहली जगह में कोण कैसे प्राप्त किया जाए, और आप यह दिखाते हैं कि ऑर्बिट को कैसे दिखाया जाए, जैसे प्रश्न पूछता है जैसे निर्देशांक खोजने के बजाय।
MichaelHouse

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