सर्कल टक्कर के अंदर सर्कल


9

मेरी एक परियोजना में मेरे पास एक सर्कल के आकार में एक खेल क्षेत्र है। इस घेरे के अंदर एक और छोटा घेरा घूम रहा है। मैं जो करना चाहता हूं वह छोटे सर्कल को बड़े से बाहर जाने से रोकना है। नीचे आप देख सकते हैं कि फ़्रेम 2 में छोटा वृत्त आंशिक रूप से बाहर है, मुझे इसे वापस स्थानांतरित करने के लिए एक तरीका चाहिए, इससे पहले कि यह बाहर स्थानांतरित होने वाला है। यह कैसे किया जा सकता है?

मूल उदाहरण

इसके अलावा, मुझे बड़े सर्कल के चाप के साथ टकराव बिंदु की आवश्यकता है ताकि मैं छोटे सर्कल के वेग को अपडेट कर सकूं। इस बिंदु की गणना कैसे होगी?

छोटे वृत्त को स्थानांतरित करने से पहले मैं क्या करना चाहूंगा, मैं इसकी अगली स्थिति की भविष्यवाणी करता हूं और अगर यह बाहर है तो मुझे t = 0 और t = 1 (t = 1 पूर्णकालिक चरण) के बीच टकराव का समय लगता है। अगर मेरे पास टक्कर का समय टी है तो मैं एक पूर्णकालिक कदम के बजाय टी के दौरान छोटे वृत्त को स्थानांतरित करता हूं। लेकिन फिर, समस्या यह है कि मुझे नहीं पता कि उस समय कैसे पता लगाया जाए कि टक्कर तब होती है जब यह दो मंडलियों में आता है और एक दूसरे के अंदर होता है।

संपादित करें:

टक्कर बिंदु (हरा) का उदाहरण मैं खोजना चाहता हूं। हो सकता है तस्वीर थोड़ी हटकर हो लेकिन आपको अंदाजा हो जाए।

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

जवाबों:


10

मान लेते हैं कि बड़े वृत्त का केंद्र Aऔर त्रिज्या है Rऔर छोटे वृत्त का केंद्र Bऔर त्रिज्या rस्थान की ओर बढ़ते हैं C

इस समस्या को हल करने का एक सुंदर तरीका है, मिन्कोवस्की रकम (घटाव, वास्तव में) का उपयोग करना: त्रिज्या की डिस्क को त्रिज्या की डिस्क के Rसाथ बदलें R-r, और त्रिज्या की डिस्क के rसाथ त्रिज्या की डिस्क 0, अर्थात। एक साधारण बिंदु पर स्थित है B। समस्या एक लाइन-सर्कल चौराहे की समस्या बन जाती है।

आपको केवल यह जांचने की आवश्यकता है कि दूरी इससे ACछोटी है या नहीं R-r। यदि यह है, तो मंडल टकराते नहीं हैं। यदि यह बड़ा है, बस बिंदु मिल Dपर BCदूरी पर R-rकी Aहै और इस अपने छोटे चक्र के केंद्र के नए स्थान है। यह ऐसा खोजने के बराबर kहै:

  vec(BD) = k*vec(BC)
and
  norm(vec(AD)) = R-r

स्थानापन्न vec(AD)के साथ vec(AB) + vec(BD)देता है:

AB² + k² BC² + 2k vec(AB).vec(BC) = (R-r

बशर्ते प्रारंभिक स्थिति बड़े सर्कल के अंदर थी, इस द्विघात समीकरण में kएक सकारात्मक जड़ है। यहाँ समीकरण को हल करने का तरीका बताया गया है, pseudocode में:

b = - vec(AB).vec(BC) / BC²    // dot product
c = (AB² - (R-r)²) / BC²
d = b*b - c
k = b - sqrt(d)
if (k < 0)
    k = b + sqrt(d)
if (k < 0)
    // no solution! we must be slightly out of the large circle

इस मान के साथ k, छोटे वृत्त का नया केंद्र Dऐसा है BD = kBC

संपादित करें : द्विघात समीकरण समाधान जोड़ें


धन्यवाद, यह सुरुचिपूर्ण दिखता है, लेकिन मुझे यकीन नहीं है कि मैं समझता हूं। उदाहरण के लिए: "R की A की दूरी पर BC पर बिंदु D को खोजें"। मैंने बेहतर समझने की कोशिश करने के लिए एक तस्वीर खींची । इसलिए यदि हम B (AX, AY- (Rr)) और C से शुरू करते हैं तो हम वर्तमान वेग के साथ समाप्त हो जाएंगे। जिस तरह से मैं उद्धृत पाठ को समझता हूं: लाइन सेगमेंट बीसी पर एक बिंदु डी ढूंढें जो ए से दूर आरआर की दूरी है। लेकिन जिस तरह से मैं इसे चित्र पर देखता हूं वह यह है कि केवल बी ए आर से दूर है। अन्य बिंदु होंगे> ए से दूर आर। मैं क्या याद कर रहा हूं?
dbostream

@dbostream आपको कुछ भी याद नहीं है। यदि दो सर्कल पहले से ही संपर्क में हैं, तो पता लगाने के लिए कोई वास्तविक टकराव नहीं है : टक्कर में होता है B, और k=0। अब यदि यह टकराव का संकल्प है , तो आप चाहते हैं, मैंने अपने उत्तर में इसे शामिल नहीं किया है क्योंकि इसमें वस्तुओं के भौतिक गुणों के बारे में ज्ञान की आवश्यकता होगी। क्या होने वाला है? क्या भीतर का घेरा उछालना चाहिए? या रोल? झाड़ू लगा दो?
सैम होसेवर

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

@dbostream अगर इस तरह से आंदोलन को विवश किया जाना चाहिए, तो मेरा सुझाव है कि आप जल्द से जल्द उस बाधा का पालन करें: यदि वेग है V, तो सर्कल V*tकी परिधि के साथ आंतरिक सर्कल को आगे बढ़ाएं R-r। इसका मतलब V*t/(R-r)बिंदु के चारों ओर कोण रेडियन का एक रोटेशन है A। और वेग वेक्टर को उसी तरह घुमाया जा सकता है। सामान्य (जो हमेशा सर्कल के केंद्र की ओर उन्मुख होता है) या किसी अन्य तरीके से वेग को अपडेट करने की आवश्यकता नहीं है।
सैम होसेवर

मुझे अभी भी घूमने से पहले छोटे सर्कल को टकराव बिंदु तक ले जाने की आवश्यकता है। और जब मैंने रोटेशन मैट्रिक्स का उपयोग करके स्थिति को घुमाए जाने की कोशिश की तो नई स्थिति बिल्कुल (लेकिन लगभग) आरआर बड़े सर्कल के केंद्र से दूर नहीं थी, लेकिन वह छोटा सा अंतर मेरे टक्कर टेस्ट को अगले रन पर विफल करने के लिए पर्याप्त था। क्या मुझे नए को खोजने के लिए स्थिति को घुमाना होगा, क्या यह सदिश संचालन का उपयोग करना संभव नहीं है जैसे आप कर सकते हैं यदि कोई सीधी दीवार से टकराता है?
dbostream

4

कहें कि बड़ा सर्कल सर्कल A है और छोटा सर्कल सर्कल B है।

यह देखने के लिए जांचें कि क्या B A के अंदर है:

distance = sqrt((B.x - A.x)^2 + (B.y - A.y)^2))
if(distance > A.Radius + B.Radius) { // B is outside A }

अगर फ्रेम n-1B A के अंदर था और nB फ्रेम A के बाहर है और फ़्रेम के बीच का समय बहुत बड़ा नहीं था (उर्फ B बहुत तेज़ नहीं चल रहा था) हम B के कार्टेशियन निर्देशांक को ढूंढकर टकराव के बिंदु को अनुमानित कर सकते हैं ए:

collision.X = B.X - A.X;
collision.Y = B.Y - A.Y;

हम इस बिंदु को एक कोण में बदल सकते हैं:

collision.Normalize(); //not 100% certain if this step is necessary     
radians = atan2(collision.Y, collision.X)

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


धन्यवाद, लेकिन क्या वास्तव में उस चौराहे का परीक्षण करते समय छोटे सर्कल के केंद्र से किरण को शूट करना सही है? क्या हम इस चित्र के बीच के परिदृश्य को समाप्त नहीं करेंगे ? मेरा मतलब है कि छोटे सर्कल के आर्क पर पहला बिंदु बड़े सर्कल के साथ टकराने के लिए आवश्यक नहीं है कि गति की दिशा में चाप पर एक है। मुझे लगता है कि मुझे जिस चित्र से जोड़ा गया है, उसके निचले परिदृश्य में मुझे कुछ चाहिए। मैंने पहली पोस्ट में एक नई तस्वीर जोड़ी है जो मुझे लगता है कि मुझे क्या चाहिए, इसका एक उदाहरण दिखा रहा है।
dbostream

हम्म मैं मानता हूं कि परिदृश्य संभव है। हो सकता है कि एक नए सर्कल C के साथ परीक्षण करें, जिसमें B.Radius + B इस फ्रेम की अधिकतम गति है, यह देखें कि क्या A से टकराता है और फिर C पर उस बिंदु को वर्कआउट करता है जो ए से फुर्सत है (यह btw की कोशिश नहीं की गई है)
रॉय T.

3
कम शब्दों का उपयोग करना: यदि (दूरी (ए, बी))> (रा-आरबी) टकराव होता है और आप बस आरए-आरबी के बराबर दूरी पाने के लिए छोटे वृत्त को घुमाते हैं। और आप छोटे वृत्त को सामान्य रूप से घुमाते हैं। जिस तरह से @dbostream आप सट्टा संपर्कों के सरलीकृत रूप के समान कुछ का उपयोग कर रहे हैं, उसके लिए खोज करने का प्रयास करें।
डार्कविंग्स

@Darkwings +1 आप बिलकुल सही कह रहे हैं, और यह बहुत आसान लग रहा है!
रॉय टी।

यह सरल लगता है क्योंकि मैंने जरूरत के सभी आधार ज्यामिति को छीन लिया। इसके बजाय इसे 'टकराव' के नामकरण के बजाय आप इसे सीमाबद्ध नाम दे सकते हैं क्योंकि वास्तव में यह है: फ्री वेक्टर एबी (0,0) से बंधा हुआ। एक बार जब आप इसे सामान्य कर लेते हैं तो आपको सीधी रेखा के AB बंडल के समानांतर और एक उपयोगी इकाई वेक्टर के लिए दोनों समीकरण मिल जाते हैं। फिर आप उस इकाई वेक्टर को किसी भी दूरी D के लिए गुणा कर सकते हैं और नव पाए गए पैरामीटर्स को A को उस टक्कर बिंदु को जोड़ सकते हैं जिसकी आपको आवश्यकता है: C (Ax + Dx, Ay + Dy)। अब यह अधिक जटिल लग रहा है लेकिन यह एक ही बात है: पी
डार्कविंग्स

0

आज्ञा देना (Xa, Ya) बड़े वृत्त की स्थिति और यह त्रिज्या R, और (Xb, Yb) छोटे वृत्त की स्थिति है और यह त्रिज्या r है।

आप जाँच कर सकते हैं कि क्या ये दो वृत्त टकराते हैं या नहीं

DistanceTest = sqrt(((Xa - Xb) ^ 2) + ((Ya - Yb) ^ 2)) >= (R - r)

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

left = 0 //the frame with no collision
right = 1 //the frame after collision
steps = 8 //or some other value, depending on how accurate you want it to be
while (steps > 0)
    checktime = left + (right - left) / 2
    if DistanceTest(checktime) is inside circle //if at the moment in the middle of the interval [left;right] the small circle is still inside the bigger one
        then left = checktime //the collision is after this moment of time
        else right = checktime //the collision is before
    steps -= 1
finaltime = left + (right - left) / 2 // the moment of time will be somewhere in between, so we take the moment in the middle of interval to have a small overall error

एक बार जब आप टकराव का समय जान लेते हैं, तो अंतिम समय पर दो मंडलियों की स्थिति की गणना करें और अंतिम टक्कर बिंदु है

CollisionX = (Xb - Xa)*R/(R-r) + Xa
CollisionY = (Yb - Ya)*R/(R-r) + Ya

0

मैं सैम Hocevar द्वारा वर्णित एल्गोरिथ्म का उपयोग करते हुए jsfiddle पर एक सर्कल में उछलती हुई गेंद के डेमो को लागू किया है :

http://jsfiddle.net/klenwell/3ZdXf/

यहाँ जावास्क्रिप्ट है जो संपर्क के बिंदु की पहचान करता है:

find_contact_point: function(world, ball) {
    // see https://gamedev.stackexchange.com/a/29658
    var A = world.point();
    var B = ball.point().subtract(ball.velocity());
    var C = ball.point();
    var R = world.r;
    var r = ball.r;

    var AB = B.subtract(A);
    var BC = C.subtract(B);
    var AB_len = AB.get_length();
    var BC_len = BC.get_length();

    var b = AB.dot(BC) / Math.pow(BC_len, 2) * -1;
    var c = (Math.pow(AB_len, 2) - Math.pow(R - r, 2)) / Math.pow(BC_len, 2);
    var d = b * b - c;
    var k = b - Math.sqrt(d);

    if ( k < 0 ) {
        k = b + Math.sqrt(d);
    }

    var BD = C.subtract(B);
    var BD_len = BC_len * k;
    BD.set_length(BD_len);

    var D = B.add(BD);
    return D;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.