मैं 2 डी आयताकार वस्तु टकराव की दिशा का कैसे पता लगा सकता हूं?


11

इस सवाल के बाद , मुझे कुछ और मदद चाहिए।

मैं कैसे पता लगा सकता हूं कि आयत के किस हिस्से से टकराव हुआ और उसी के अनुसार प्रतिक्रिया हुई?

आयतों को सभी पक्षों से टकराया जा रहा है

नीले तीर वे पथ होते हैं जिन्हें कुछ गोलाकार वस्तुएं बॉक्स से टकराने से पहले और बाद में देखती हैं।

मैं इसकी गणना कैसे कर सकता हूं?

जवाबों:


8

चूंकि यह आपके अन्य प्रश्न पर आधारित है, इसलिए जब आयत को अक्ष-संरेखित किया जाता है, तो मैं इसका समाधान दूंगा।

पहले, आप निम्न मूल्यों के साथ वर्तमान वस्तु की आयत बनाते हैं:

int boxLeft = box.X;
int boxRight = boxLeft + box.Width;
int boxTop = box.Y;
int boxBottom = boxTop + box.Height;

अगला, आपके पास पुरानी वस्तु की आयत बनाने के लिए पुरानी वस्तु की स्थिति होनी चाहिए (जिसे आप प्रत्येक वस्तु पर स्टोर कर सकते हैं या किसी फ़ंक्शन में पास कर सकते हैं) (जब यह टकरा नहीं रहा था):

int oldBoxLeft = box.OldX;
int oldBoxRight = oldBoxLeft + box.Width;
int oldBoxTop = box.OldY;
int oldBoxBottom = oldBoxTop + box.Height;

अब, यह जानने के लिए कि टक्कर कहाँ से थी, आपको उस पक्ष का पता लगाना चाहिए जहाँ पुरानी स्थिति टकराव क्षेत्र में नहीं थी और जहाँ उसकी स्थिति ठीक है। क्योंकि, जब आप इसके बारे में सोचते हैं, तो यही होता है जब आप टकराते हैं: एक ऐसा पक्ष जो टकरा नहीं रहा था वह एक अन्य आयत में प्रवेश करता है।

यहां बताया गया है कि आप ऐसा कैसे कर सकते हैं (ये कार्य यह मानते हैं कि टक्कर है। यदि कोई टक्कर नहीं है तो उन्हें नहीं बुलाया जाना चाहिए):

 bool collidedFromLeft(Object otherObj)
{
    return oldBoxRight < otherObj.Left && // was not colliding
           boxRight >= otherObj.Left;
}

फिर से करना और दोहराना

bool collidedFromRight(Object otherObj)
{
    return oldBoxLeft >= otherObj.Right && // was not colliding
           boxLeft < otherObj.Right;
}

bool collidedFromTop(Object otherObj)
{
    return oldBoxBottom < otherObj.Top && // was not colliding
           boxBottom >= otherObj.Top;
}

bool collidedFromBottom(Object otherObj)
{
    return oldBoxTop >= otherObj.Bottom && // was not colliding
           boxTop < otherObj.Bottom;
}

अब, अन्य प्रश्न से टकराव की प्रतिक्रिया के साथ वास्तविक उपयोग के लिए:

if (collidedFromTop(otherObj) || collidedFromBottom(otherObj))
    obj.Velocity.Y = -obj.Velocity.Y;
if (collidedFromLeft(otherObj) || collidedFromRight(otherObj))
    obj.Velocity.X = -obj.Velocity.X;

फिर से, यह सबसे अच्छा समाधान नहीं हो सकता है लेकिन यही वह तरीका है जो मैं आमतौर पर टकराव का पता लगाने के लिए जाता हूं।


एक बार फिर, आप सही थे! ; D धन्यवाद ... (अगली बार मुझे अपने बोर्ड के अधिक पोस्टकार्ड भेजें ... ^ ___ ^)
नेमोसेटिन

अहह दुख की बात है कि मुझे नहीं पता था कि मैं इसके लिए क्या इस्तेमाल कर सकता हूँ .. शायद अगली बार!
जेसी इमोंड

7

जैसा कि प्रश्न आंशिक रूप से इस प्रश्न के समान है , मैं आपके प्रश्न के उत्तर देने के लिए अपने उत्तर के कुछ हिस्सों का पुनः उपयोग करूंगा।


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

तो, हम एक एक्सिस एलाइनड बाउंडिंग बॉक्स (या एक ओरिएंटेड बाउंडेड बॉक्स ) और एक पर विचार करेंगे चलती एंटिटी पर विचार करेंगे

  • बाउंडिंग बॉक्स 4 पक्षों से बना है, और हम प्रत्येक को एक के रूप में परिभाषित करेंगे:
    साइड 1 = [एक्स 1, वाई 1 , एक्स 2, वाई 2 ] (दो अंक [एक्स 1, वाई 1] और [एक्स 2, ])

  • मूविंग एंटिटी को एक वेग वेक्टर (स्थिति + गति) के रूप में परिभाषित किया गया है:
    एक स्थिति [पॉज़, पॉसी] और एक गति [स्पीडएक्स, स्पीडी]


आप निर्धारित कर सकते हैं कि AABB / OBB का कौन सा भाग निम्नलिखित विधि का उपयोग करके वेक्टर द्वारा मारा जाता है:

  • 1 / AABB के चार भुजाओं और इकाई स्थिति (पूर्व-टकराव) से गुजरने वाली अनंत रेखा के बीच गुजरने वाली अनंत रेखाओं के बीच चौराहे के बिंदु खोजें जो ढलान के रूप में इकाई गति वेक्टर का उपयोग करते हैं। (आप या तो टकराव बिंदु या अपरिभाषित संख्या पा सकते हैं, जो समानताएं या अतिव्यापी लाइनों से मेल खाती है)

  • 2 / एक बार जब आप चौराहे के बिंदुओं को जानते हैं (यदि वे मौजूद हैं) तो आप उन लोगों को खोज सकते हैं जो खंड सीमा में हैं।

  • 3 / अंत में, अगर सूची में अभी भी कई बिंदु हैं (वेग वेक्टर कई पक्षों से गुजर सकता है), तो आप इकाई उत्पत्ति से निकटतम बिंदु के लिए वेक्टर के परिमाण का उपयोग करके इकाई मूल से खोज सकते हैं।

फिर आप एक साधारण डॉट उत्पाद का उपयोग करके टकराव के कोण को निर्धारित कर सकते हैं।

  • 4 / इकाई के डॉट उत्पाद (शायद एक गेंद?) का उपयोग करके टकराव के बीच के कोण को हिट हिट वेक्टर से सदिश करें।

----------

अधिक जानकारी:

  • 1 / चौराहों का पता लगाएं

    • a / उनके पैरामीट्रिक फॉर्म (P (t) = Po + tD) का उपयोग करके अनंत रेखाओं (Ax + Bx = D) का निर्धारण करते हैं।

      बिंदु उत्पत्ति: पो = [पॉसएक्स, पॉसी]
      दिशा सदिश: डी = [स्पीडएक्स, स्पीडी]

      = डाई = गति
      बी = -एक्सएक्सएक्स -स्पीडएक्स
      डी = (पीओएक्स * डाई) - (पीओ। एक्स * एक्स) = (posX speedY) - (पॉसी स्पीडएक्स)

      Ax + By = D <====> (speedy x) + (-speedX y) = (posX speedY) - (posy speedX)

      मैंने विधि को चित्रित करने के लिए इकाई बिंदु मानों का उपयोग किया, लेकिन यह बाउंडिंग बॉक्स की 4 साइड अनंत रेखाओं का निर्धारण करने के लिए ठीक यही विधि है (Use Po = [X1, y1] और D = [x2-X1; y2-y1] बजाय)।

    • b / अगला, दो अनंत रेखाओं के प्रतिच्छेदन को खोजने के लिए हम निम्नलिखित प्रणाली को हल कर सकते हैं:

      A1x + B1x = D1 <== स्लिप के रूप में गति वेक्टर के साथ इकाई बिंदु से गुजरने वाली रेखा।
      A2x + B2x = D2 <== AABB पक्षों से गुजरने वाली लाइनों में से एक।

      जो अवरोधन के लिए निम्नलिखित निर्देशांक देता है:

      अवरोधन x = (( B 2 * D 1) - ( B 1 * D 2)) / (( A 1 * B 2) - ( A 2 * B 1))
      Interception y = (( A 1 * D 2) - ( २ * डी १)) / (( १ * बी २) - ( २ * बी १))

      यदि भाजक ((ए 1 * बी 2) - (ए 2 * बी 1)) शून्य के बराबर है, तो दोनों रेखाएं समानताएं या अतिव्यापी हैं, अन्यथा आपको एक चौराहा मिलना चाहिए।

  • खंड सीमा के लिए 2 / टेस्ट। चूंकि यह सत्यापित करने के लिए सीधा है, इसलिए अधिक विवरण की आवश्यकता नहीं है।

  • 3 / निकटतम बिंदु के लिए खोजें। यदि सूची में अभी भी कई बिंदु हैं, तो हम पा सकते हैं कि कौन सा पक्ष इकाई मूल बिंदु के सबसे निकट है।

    • ए / चौराहे बिंदु से इकाई मूल बिंदु तक जाने वाले वेक्टर को निर्धारित करें

      वी = पो - इंट = [पीओ.एक्स - इंट.एक्स; Po.y - Int.y]

    • b / वेक्टर परिमाण की गणना

      || वी || = sqrt (V.x² + V.yrt)

    • c / सबसे छोटा खोजो।
  • 4 / अब जब आप जानते हैं कि कौन सा पक्ष मारा जाएगा, तो आप एक डॉट उत्पाद का उपयोग करके कोण निर्धारित कर सकते हैं।

    • a / Let S = [x2-X1; y2-y1] साइड वेक्टर होगा जो हिट होगा और E = [speedX; speedY] इकाई वेग वेक्टर हो।

      वेक्टर डॉट उत्पाद नियम का उपयोग करके हम जानते हैं कि

      S · E = Sx Ex + Sy आँख
      और
      S · E = || S || || ई || cos θ

      इसलिए हम इस समीकरण को थोड़ा जोड़कर we निर्धारित कर सकते हैं ...

      cos cos = (एस · ई) / ((एस। एस। ई।)

      θ = एसोस ((एस ·)) / ((एस || ई।)) ||

      साथ में

      S · E = Sx * Ex + Sy * आँख
      || S || = sqrt (Sx² + Sy²)
      || ई || = sqrt (Ex sq + Ey²)


नोट: जैसा कि मैंने दूसरे प्रश्न सूत्र में कहा है, यह शायद सबसे कुशल और न ही सबसे सरल तरीका है, यह सिर्फ वही है जो दिमाग में आया है, और गणित का कुछ हिस्सा शायद मदद कर सकता है।

मैंने एक ठोस OBB उदाहरण के साथ सत्यापित नहीं किया था (मैंने AABB के साथ किया था) लेकिन यह भी काम करना चाहिए।


6

एक सरल तरीका टकराव को हल करना है, फिर चलती वस्तु के टकराव के बक्से को बारी-बारी से प्रत्येक दिशा में एक पिक्सेल से अनुवाद करें और देखें कि किन लोगों में टक्कर होती है।

यदि आप इसे "ठीक से" करना चाहते हैं और घुमाए गए टकराव की आकृतियों या मनमाने बहुभुजों के साथ, मैं अलग एक्सिस प्रमेय पर पढ़ने का सुझाव देता हूं। उदाहरण के लिए मेटनेट सॉफ्टवेयर (एन गेम बनाने वाले लोग) का SAT पर एक भयानक देव लेख है । वे इसमें शामिल भौतिकी पर भी चर्चा करते हैं।


2

एक तरीका यह होगा कि आप अपनी आयत के आसपास की दुनिया को घुमाएँ। इस मामले में "दुनिया" केवल उन वस्तुओं के बारे में है जिनकी आप परवाह करते हैं: आयत, और गेंद। आप इसके केंद्र के चारों ओर आयत को घुमाते हैं जब तक कि इसकी सीमाएँ x- / y-axes के साथ संरेखित नहीं हो जाती हैं, तब आप उसी राशि से गेंद को घुमाते हैं।

यहां महत्वपूर्ण बिंदु यह है कि आप गेंद को आयत के केंद्र के चारों ओर घुमाते हैं, न कि स्वयं के।

फिर आप आसानी से टक्कर के लिए परीक्षण कर सकते हैं जैसे आप किसी अन्य गैर-घुमाए गए आयत के साथ करेंगे।


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


1

मैंने अपनी गणना में निश्चित कोणों का उपयोग किया, लेकिन इससे आपको कुछ मदद मिलनी चाहिए

void Bullet::Ricochet(C_Rect *r)
{
    C_Line Line;
    //the next two lines are because I detected 
    // a collision in my main loop so I need to take a step back.

    x = x + ceil(speed * ((double)fcos(itofix(angle)) / 65536));
    y = y + ceil(speed * ((double)fsin(itofix(angle)) / 65536));
    C_Point Prev(x,y);

    //the following checks our position to all the lines will give us
    // an answer which line we will hit due to no lines
    // with angles > 90 lines of a rect always shield the other lines.

    Line = r->Get_Closest_Line(Prev);    
    int langle = 0;
    if(!Line.Is_Horizontal())   //we need to rotate the line to a horizontal position
    {
        langle = Line.Get_Point1().Find_Fixed_Angle(Line.Get_Point2());
        angle = angle - langle;  //to give us the new angle of approach
    }
    //at this point the line is horizontal and the bullet is ready to be fixed.
    angle = 256 - angle;
    angle += langle;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.