मेरे पास कुछ के साथ टकराव होने पर वेग को शून्य पर सेट करने के लिए एक साधारण स्क्रिप्ट है, लेकिन ऐसा लगता है कि यह तुरंत काम नहीं करेगा:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MoveController : MonoBehaviour {

    [SerializeField]
    private float shootVelocity=30f;

    void Start () {

    }

    private void OnGUI()
    {
        if(GUI.Button(new Rect(0,0,100,100), "shoot"))
        {
            GetComponent<Rigidbody>().velocity = shootVelocity * Vector3.forward;
        }
    }

    private void OnCollisionEnter(Collision collision)
    {
        GetComponent<Rigidbody>().velocity = Vector3.zero;
        GetComponent<Rigidbody>().isKinematic = true;
    }

}

मैंने समस्या को प्रदर्शित करने के लिए एक youtube वीडियो भी बनाया है।

टक्कर होने के तुरंत बाद गेंद को रोकना वास्तव में महत्वपूर्ण है।

उसको कैसे करे?

0
armnotstrong 8 पद 2017, 14:12

2 जवाब

आपको यह समस्या इसलिए आती है क्योंकि एक विशिष्ट समय चरण होता है जिसके बाद भौतिकी की गणना होती है, आप इसके बारे में अधिक पढ़ सकते हैं https://docs.unity3d.com/Manual/class-TimeManager.html

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

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

मैं आपको उदाहरण दूंगा कि कैसे सही रुकने की स्थिति की गणना करें (वह स्थिति जहां दो वस्तुएं एक बिंदु पर स्पर्श कर रही हैं) यदि वस्तु हमेशा एक ही दिशा में आगे बढ़ रही है जब वह दूसरी वस्तु से गुजर रही है और आप दो गोलाकार कोलाइडर के साथ काम कर रहे हैं जिनकी त्रिज्या दुनिया में है पैमाने आप जानते हैं। आइए उन्हें त्रिज्या 1 और त्रिज्या 2 नाम दें, और पैरामीटर "टी" जो दर्शाता है कि सही टकराव की स्थिति प्राप्त करने के लिए कितनी आगे/पीछे की वस्तु को स्थानांतरित करने की आवश्यकता है।

जब टक्कर का पता चलता है तो आप निम्नलिखित गणना कर सकते हैं।

Vector3 firstVector = transform.position-collidedObject.transform.position; Vector3 secondVector = direction; float r = radius1+radius2;

(पहला वेक्टर - दूसरा वेक्टर * टी)। वर्ग परिमाण = आर ^ 2;

अपने समीकरण का विस्तार करें यहां छवि विवरण दर्ज करें

या टेक्स्ट मोड में =\sqrt{2x_2^2t^2+z_2^2t^2-2x_1x_2t-2z_1x_2t-2z_1z_2t+x_1^2+2z_1^2}

अब टी के लिए हल करें और आपको दो मान मिलेंगे, क्योंकि आपके पास दी गई दिशा के लिए दो सही टकराव की स्थिति है (एक दूसरी वस्तु से पहले और एक के बाद)।

आपको यह समीकरण मिलता है यहां छवि विवरण दर्ज करें प्रतीक समीकरणों से लिंक करें

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

मान लें कि अब आपके पास समीकरण के मानों के साथ "t1" और "t2" है, अब आप कर सकते हैं

float finalT = Mathf.Abs(t1) < Mathf.Abs(t2) ? t1 : t2;
transform.position += dir*t;

आपको इन सब की गणना तभी करनी होगी जब टक्कर का पता चले, मैं यह भी सुझाव दूंगा कि ऐसा तभी करें जब:

if((transform.position-collidedObject.transform.position).sqrMagnitude > (radius1+radius2 + someThresholdValue)^2)

तो आप गणना को अनदेखा करते हैं यदि ऑब्जेक्ट्स पहले से ही एकता इंजन द्वारा बहुत अच्छी तरह से स्थित हैं। मुझे बताएं कि यह कैसा चल रहा है, आशा है कि यह मदद करता है!

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

1
Neven Ignjic 8 पद 2017, 15:23
धन्यवाद, नेवेन, मैं इसे समझने की कोशिश करूंगा और कोशिश करूंगा और आपको बता दूंगा (इसमें कुछ समय लग सकता है) एक चीज जो मैंने सुनिश्चित करने की कोशिश की है, निश्चित टाइमस्टैम्प को छोटा करने से अधिक सटीक स्थिति मिलती है
 – 
armnotstrong
8 पद 2017, 15:37

इस तरह भौतिकी काम करती है।

यदि गतिमान वस्तु का वेग अधिक है, तो उसका संवेग अधिक होगा इसलिए रुकने में अधिक समय लगेगा।

आप इसे और अधिक कुशल बनाने के लिए अपने कोड को इस तरह अपडेट करने का प्रयास कर सकते हैं।

public class MoveController : MonoBehaviour 
{

    [SerializeField]
    private float shootVelocity=30f;

    Rigidbody rb;
    void Start () 
    {
        rb = GetComponent<Rigidbody>();
    }

    private void OnGUI()
    {
        if(GUI.Button(new Rect(0,0,100,100), "shoot"))
        {
            rb.velocity = shootVelocity * Vector3.forward;
        }
    }

    private void OnCollisionEnter(Collision collision)
    {
        rb.isKinematic = true;  
        rb.velocity = Vector3.zero;
        rb.angularVelocity = Vector3.zero;
    }
}

उम्मीद है ये मदद करेगा :)

0
Umair M 8 पद 2017, 14:51
आपके उत्तर के लिए धन्यवाद लेकिन लगता है कि rb.angularVelocity=Vect3.zero जोड़ने से बहुत मदद नहीं मिली :-(
 – 
armnotstrong
8 पद 2017, 15:11
मैंने केवल इतना ही नहीं बदला है, पूर्व-प्राप्त कठोर शरीर संदर्भ सूक्ष्म-स्तर पर चीजों को गति देगा। आप स्थिति बाधाओं के साथ खेलते हुए, विभिन्न कठोर टक्कर मोड (असतत/निरंतर), बढ़ते/घटते द्रव्यमान को भी आजमा सकते हैं। इन सभी विकल्पों को रिजिडबॉडी इंस्पेक्टर में देखें
 – 
Umair M
8 पद 2017, 15:13
हम्म, क्या आपका मतलब Rigidbody को आरक्षित संदर्भ बनाकर करना है? बस मेरे कोड को अपने साथ बदलें, यह सब समान लगता है।
 – 
armnotstrong
8 पद 2017, 15:17
घटकों के संदर्भ को हमेशा एक चर में संग्रहीत करें। GetComponent<> कॉल कुछ प्रोसेसिंग लेता है। और टकराने पर सबसे पहले IsKinematic सेट करें
 – 
Umair M
8 पद 2017, 15:20