एक 2 डी भौतिकी इंजन में रैपिंग वायर (वर्म्स निंजा रस्सी की तरह) को लागू करना


34

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

गेमप्ले के लिए, रस्सी के लिए पर्यावरण के चारों ओर लपेटने की क्षमता और फिर बाद में खोलना महत्वपूर्ण है। यह रस्सी की तरह व्यवहार भी नहीं करता है - एक "तार" जो सीधी रेखा के खंडों से बना होता है। यहाँ एक उदाहरण है:

निंजा रस्सी, बाधाओं के आसपास लपेटकर

यह खेल कीड़े से "निंजा रस्सी" के समान है।

क्योंकि मैं 2D भौतिकी इंजन का उपयोग कर रहा हूँ - मेरा वातावरण 2D उत्तल बहुभुज से बना है। (विशेष रूप से मैं Farseer में SAT का उपयोग कर रहा हूं।)

तो मेरा सवाल यह है: आप "रैपिंग" प्रभाव को कैसे लागू करेंगे?

यह बहुत स्पष्ट लगता है कि तार लाइन सेगमेंट की एक श्रृंखला से बना होगा जो "विभाजित" और "जॉइन" है। और उस लाइन का अंतिम (सक्रिय) खंड, जहां चलती वस्तु संलग्न होती है, एक निश्चित लंबाई वाली संयुक्त होगी।

लेकिन सक्रिय लाइन खंड को कब और कहां विभाजित किया जाना है, यह निर्धारित करने के लिए गणित / एल्गोरिथ्म क्या शामिल है? और जब इसे पिछले सेगमेंट के साथ जुड़ने की आवश्यकता है?

(पहले इस प्रश्न को गतिशील वातावरण के लिए करने के बारे में भी पूछा गया था - मैंने उस बंद को अन्य प्रश्नों में विभाजित करने का निर्णय लिया है।)

जवाबों:


18

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

निंजा रस्सी की स्थिति का सहायक चित्र

जिस तरह से आप टकराव का पता लगाते हैं, वह यह है कि वर्तमान रस्सी खंड की जड़ के लिए, O, पिछले फ्रेम पर रस्सी की अंतिम स्थिति, A, वर्तमान फ्रेम पर रस्सी की अंतिम स्थिति, बी, और एक बहुभुज में प्रत्येक कोने बिंदु P स्तर ज्यामिति, आप गणना करते हैं (OA x OP), (OP x OB) और (OA x OB), जहां "x" दो वैक्टरों के बीच क्रॉस उत्पाद के Z समन्वय को दर्शाता है। यदि सभी तीन परिणामों में एक ही चिन्ह, नकारात्मक या सकारात्मक है, और ओपी की लंबाई रस्सी खंड की लंबाई से छोटी है, तो बिंदु पी स्विंग द्वारा कवर किए गए क्षेत्र के भीतर है, और आपको रस्सी को विभाजित करना चाहिए। यदि आपके पास कई टकराने वाले कोने बिंदु हैं, तो आप पहले वाले को रस्सी से मारना चाहते हैं, जिसका अर्थ है कि OA और OP के बीच का कोण सबसे छोटा है। कोण निर्धारित करने के लिए डॉट उत्पाद का उपयोग करें।

सेगमेंट में शामिल होने के लिए, पिछले सेगमेंट और अपने वर्तमान सेगमेंट के आर्क के बीच तुलना करें। यदि वर्तमान खंड बाईं ओर से दाईं ओर या इसके विपरीत घूम गया है, तो आपको खंडों में शामिल होना चाहिए।

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

यह विधि निश्चित रूप से मानती है कि आप रस्सी से लटकी हुई वस्तु के लिए टकराव का पता लगा रहे हैं, ताकि यह स्तर ज्यामिति के अंदर खत्म न हो।


1
इस दृष्टिकोण के साथ समस्या यह है कि फ्लोटिंग-पॉइंट सटीक त्रुटियां रस्सी के लिए "एक बिंदु" के माध्यम से जाना संभव बनाती हैं।
एंड्रयू रसेल

16

यह थोड़ी देर के बाद से मैंने कीड़े को खेला है, लेकिन मुझे जो याद है - जब रस्सी चीजों के चारों ओर घूमती है, तो रस्सी का केवल एक (सीधा) खंड होता है जो किसी भी समय बढ़ रहा है। बाकी रस्सी स्थिर हो जाती है

इसलिए इसमें बहुत कम वास्तविक भौतिकी शामिल है। सक्रिय अनुभाग को अंत में एक द्रव्यमान के साथ एक एकल कठोर वसंत के रूप में तैयार किया जा सकता है

दिलचस्प बिट सक्रिय अनुभाग से रस्सी के निष्क्रिय वर्गों को विभाजित / शामिल करने के लिए तर्क होगा।

मुझे लगता है कि 2 मुख्य ऑपरेशन होंगे:

'स्प्लिट' - रस्सी ने किसी चीज़ को काट दिया है। इसे चौराहे पर एक निष्क्रिय अनुभाग और नए, छोटे, सक्रिय अनुभाग में विभाजित करें

'ज्वाइन करें' - सक्रिय रस्सी एक ऐसी स्थिति में चली गई है जहां निकटतम चौराहा अब मौजूद नहीं है (यह सिर्फ एक सरल कोण-डॉट उत्पाद परीक्षण हो सकता है?)। एक नया, लंबा, सक्रिय खंड बनाते हुए 2 खंडों को फिर से जोड़ लें

2 डी बहुभुजों से निर्मित एक दृश्य में, सभी विभाजन बिंदु टकराव की जाली पर एक शीर्ष पर होना चाहिए। टकराव का पता लगाने के साथ कुछ सरल हो सकता है 'यदि रस्सी इस अद्यतन पर एक शीर्ष पर गुजरती है, तो उस शीर्ष पर रस्सी को विभाजित / जोड़ दें?


2
यह आदमी मौके पर सही था ... वास्तव में, यह एक "कठोर" वसंत नहीं है, आप केवल कुछ सीधी रेखा के चारों ओर घूमते हैं ...
स्पीड

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

3

Gusanos में निंजा रस्सी को कैसे लागू किया गया था, यह देखें:

  • रस्सी तब तक कण की तरह काम करती है जब तक वह किसी चीज से जुड़ नहीं जाती।
  • एक बार संलग्न होने पर, रस्सी केवल कृमि पर एक बल लगाती है।
  • इस कोड में गतिशील वस्तुओं (अन्य कीड़े की तरह) से जुड़ना अभी भी एक TODO: है।
  • मुझे याद नहीं आ रहा है यदि वस्तुओं / कोनों के चारों ओर लपेटने का समर्थन किया जाता है ...

निंजाप्रॉप से प्रासंगिक अंश ।pp :


void NinjaRope::think()
{
    if ( m_length > game.options.ninja_rope_maxLength )
        m_length = game.options.ninja_rope_maxLength;

    if (!active)
        return;

    if ( justCreated && m_type->creation )
    {
        m_type->creation->run(this);
        justCreated = false;
    }

    for ( int i = 0; !deleteMe && i < m_type->repeat; ++i)
    {
        pos += spd;

        BaseVec<long> ipos(pos);

        // TODO: Try to attach to worms/objects

        Vec diff(m_worm->pos, pos);
        float curLen = diff.length();
        Vec force(diff * game.options.ninja_rope_pullForce);

        if(!game.level.getMaterial( ipos.x, ipos.y ).particle_pass)
        {
            if(!attached)
            {
                m_length = 450.f / 16.f - 1.0f;
                attached = true;
                spd.zero();
                if ( m_type->groundCollision  )
                    m_type->groundCollision->run(this);
            }
        }
        else
            attached = false;

        if(attached)
        {
            if(curLen > m_length)
            {
                m_worm->addSpeed(force / curLen);
            }
        }
        else
        {
            spd.y += m_type->gravity;

            if(curLen > m_length)
            {
                spd -= force / curLen;
            }
        }
    }
}

1
उम्म ... यह मेरे सवाल का जवाब नहीं लगता है। मेरे सवाल का पूरा बिंदु बहुभुज से बनी दुनिया के चारों ओर एक रस्सी लपेट रहा है। Gusanos के लिए कोई लपेटकर और एक बिटमैप दुनिया है लगता है।
एंड्रयू रसेल

1

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

मुझे लगता है कि केवल कोने की बात है। यदि आपको किसी बाधा पर कोने के बीच एक खंड से टकराने का खतरा है, तो रस्सी के अंत में लटकने वाले व्यक्ति के लिए आपकी सामान्य टक्कर का पता लगाना चाहिए। दूसरे शब्दों में, आपकी रस्सी केवल "स्नैग" पर जा रही है कोनों वैसे भी, तो बीच के क्षेत्रों में कोई फर्क नहीं पड़ेगा।

क्षमा करें, मेरे पास कुछ भी ठोस नहीं है, लेकिन उम्मीद है कि यह आपको वैसा बनाने के लिए, जहां आपको वैचारिक रूप से होना चाहिए। :)


1

यहां एक पोस्ट है जिसमें समान प्रकार के सिमुलेशन के बारे में कागजात के लिंक हैं (इंजीनियरिंग / अकादमिक संदर्भों में खेलों के बजाय): https://gamedev.stackexchange.com/a/10350/6398

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

पाकुजा का जवाब अच्छा है, आप उस समय के लिए हल करके निरंतर टकराव का पता लगा सकते हैं जब तीन बिंदुओं पर हस्ताक्षर किए गए क्षेत्र 0 है।

(मैं पूरी तरह से OTOH को याद नहीं कर सकता, लेकिन आप इसे इस प्रकार देख सकते हैं: वह समय t खोजें जब बिंदु a, b, c से होकर गुजरने वाली रेखा में समाहित हो, (मुझे लगता है कि मैंने यह तब के लिए हल करके किया है जब dot (ab, cb) = टी के मूल्यों को खोजने के लिए 0), और फिर एक मान्य समय दिया गया 0 <= t <1, खंड बीसी पर पैरामीट्रिक स्थिति का पता लगाएं, यानी एक = (1-एस) बी + सी और यदि एक के बीच है b और c (अर्थात यदि ० <= s = १) यह एक वैध टक्कर है।

AFAICR आप इसे दूसरे तरीके से भी देख सकते हैं (यानी एस के लिए हल करें और फिर इसे टी खोजने के लिए प्लग करें) लेकिन यह बहुत अधिक सहज है। (मुझे खेद है अगर इसका कोई मतलब नहीं है, मेरे पास अपने नोट्स खोदने का समय नहीं है और यह कुछ साल रहा है!)

तो, अब आप उन सभी समयों की गणना कर सकते हैं, जिन पर घटनाएं होती हैं (यानी रस्सी के नोड्स को डाला या हटाया जाना चाहिए); जल्द से जल्द घटना की प्रक्रिया करें (एक नोड को सम्मिलित करें या निकालें) और फिर दोहराएं / तब तक दोहराएं जब तक कि टी = 0 और टी = 1 के बीच कोई और घटना न हो।

इस दृष्टिकोण के बारे में एक चेतावनी: यदि वे वस्तुएँ जो रस्सी के चारों ओर लपेट सकती हैं, वे गतिशील हैं (विशेषकर यदि आप उनका अनुकरण कर रहे हैं और रस्सी पर उनका प्रभाव, और इसके विपरीत) तो समस्याएँ हो सकती हैं यदि उन वस्तुओं को क्लिप / प्रत्येक के माध्यम से गुजरता है अन्य - तार पेचीदा हो सकते हैं। और यह निश्चित रूप से एक बॉक्स 2 डी-शैली भौतिकी सिमुलेशन में इस तरह की बातचीत / आंदोलन (एक दूसरे के माध्यम से फिसलने वाली वस्तुओं के कोनों) को रोकने के लिए चुनौतीपूर्ण होगा .. वस्तुओं के बीच पैठ की छोटी मात्रा उस संदर्भ में सामान्य व्यवहार है।

(कम से कम .. यह "तार" के मेरे कार्यान्वयन में से एक के साथ एक समस्या थी।)

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

मुझे लगता है कि पेकुजा का दृष्टिकोण इसके लिए भी काम करता है, हालांकि वैकल्पिक दृष्टिकोण हैं। एक दृष्टिकोण जो मैंने प्रयोग किया है वह है सहायक टक्कर डेटा जोड़ना: दुनिया के प्रत्येक उत्तल शीर्ष पर v (अर्थात आकृतियों के कोने जो रस्सी को चारों ओर लपेट सकते हैं), एक बिंदु u जोड़कर निर्देशित रेखा खंड uv बनाते हैं, जहाँ u कुछ होता है बिंदु "कोने के अंदर" (यानी दुनिया के अंदर, "पीछे" v; यू की गणना करने के लिए आप अपने इंटरपोल किए गए सामान्य के साथ v से किरण की आवक डाल सकते हैं और v के बाद कुछ दूरी रोक सकते हैं या इससे पहले कि किरण दुनिया के एक किनारे के साथ और पीछे हो जाए) ठोस क्षेत्र से बाहर निकलता है। या, आप बस विज़ुअल टूल / लेवल एडिटर का उपयोग करके दुनिया में सेगमेंट को मैन्युअल रूप से पेंट कर सकते हैं)।

वैसे भी, अब आपके पास "कॉर्नर लिनिग्स" का एक सेट है; प्रत्येक यूवी के लिए, और तार में प्रत्येक खंड ab, और uv intersect (यानी स्टेटिक, बूलियन लेनिगस-लेनिंज चौराहा क्वेरी) की जाँच करें; यदि हां, तो पुनरावृत्ति (एवी और वीबी में लिनिग एब को विभाजित करें, अर्थात वी डालें), रिकॉर्डिंग करें कि रस्सी किस दिशा में v पर झुकती है। फिर पड़ोसी लिनिग्स एब के प्रत्येक जोड़े के लिए, तार में बीसी, परीक्षण करें यदि बी पर वर्तमान मोड़ दिशा। जब बी उत्पन्न हुआ था (इन सभी "मोड़ दिशा" परीक्षण सिर्फ हस्ताक्षरित-क्षेत्र परीक्षण हैं) के समान है; यदि नहीं, तो दो सेगमेंट को ac में मर्ज करें (यानी b निकालें)।

या शायद मैं विलीन हो गया और फिर विभाजित हो गया, मैं भूल गया - लेकिन यह निश्चित रूप से कम से कम दो संभावित आदेशों में से एक में काम करता है! :)

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

वैसे भी, उम्मीद है कि यह कुछ काम का होगा ... मैंने जिस पोस्ट को लिंक किया है उसमें कागजात भी आपको कुछ विचार देने चाहिए।


0

इसके लिए एक दृष्टिकोण रस्सी को टक्कर के कणों के रूप में मॉडल करना है, जो स्प्रिंग्स द्वारा जुड़ा हुआ है। (काफी कठोर, संभवतः यहां तक ​​कि केवल एक हड्डी के बजाय)। कण पर्यावरण से टकराते हैं, जिससे यह सुनिश्चित होता है कि रस्सी वस्तुओं के चारों ओर घूमती है।

यहाँ स्रोत के साथ एक डेमो है: http://www.ewjordan.com/rgbDemo/

(पहले स्तर पर दाईं ओर ले जाएं, एक लाल रस्सी है जिसे आप बातचीत कर सकते हैं)


2
उह - यह विशेष रूप से है जो मैं नहीं चाहता (प्रश्न देखें)।
एंड्रयू रसेल

आह। यह मूल प्रश्न से स्पष्ट नहीं था। इतना स्पष्ट करने के लिए समय निकालने के लिए धन्यवाद। (महान आरेख!) मैं अभी भी बहुत छोटे निश्चित जोड़ों की एक श्रृंखला के साथ जाऊंगा, जैसा कि गतिशील विभाजन करने का विरोध किया जाता है - जब तक कि यह आपके पर्यावरण में एक बड़ा प्रदर्शन मुद्दा नहीं है, यह कोड करना बहुत आसान है।
राचेल ब्लम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.