खोज…


वाक्य - विन्यास

  • सार्वजनिक Coroutine StartCoroutine (IEnumerator दिनचर्या);
  • सार्वजनिक Coroutine StartCoroutine (स्ट्रिंग विधि नाम, वस्तु मान = अशक्त);
  • सार्वजनिक शून्य StopCoroutine (स्ट्रिंग मेथडनाम);
  • सार्वजनिक शून्य StopCoroutine (IEnumerator दिनचर्या);
  • सार्वजनिक शून्य StopAllCoroutines ();

टिप्पणियों

प्रदर्शन के विचार

मॉडरेशन में कोरआउट का उपयोग करना सबसे अच्छा है क्योंकि लचीलापन प्रदर्शन लागत के साथ आता है।

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

YieldInstructions को कैशिंग करके कचरा कम करें

YieldInstruction में उत्पन्न कचरे को कम करने के लिए एक आम चाल YieldInstruction को कैश करना है।

IEnumerator TickEverySecond()
{
    var wait = new WaitForSeconds(1f); // Cache
    while(true)
    {
        yield return wait; // Reuse
    }
}

पैदावार null कोई अतिरिक्त कचरा पैदा करता है।

Coroutines

पहले यह समझना आवश्यक है कि, खेल इंजन (जैसे कि एकता) एक "फ्रेम आधारित" प्रतिमान पर काम करते हैं।

हर फ्रेम के दौरान कोड निष्पादित किया जाता है।

जिसमें यूनिटी का अपना कोड और आपका कोड शामिल है।

जब फ्रेम के बारे में सोच है, यह समझने के लिए पूरी तरह से जब फ्रेम होने की कोई गारंटी नहीं है कि वहाँ महत्वपूर्ण है। वे नियमित बीट पर नहीं होते हैं। फ्रेम के बीच अंतराल उदाहरण के लिए, 0.02632 फिर 0.021167 फिर 0.029778, और इसी तरह हो सकता है। उदाहरण में वे सभी "एक सेकंड के 1/50 वें" के बारे में हैं, लेकिन वे सभी अलग हैं। और किसी भी समय, आपको एक फ्रेम मिल सकता है जो अधिक समय लेता है, या कम; और आपके कोड को फ्रेम के भीतर किसी भी समय निष्पादित किया जा सकता है।

ध्यान में रखते हुए, आप पूछ सकते हैं: आप इन फ़्रेम को अपने कोड में, यूनिटी में कैसे एक्सेस कर सकते हैं?

काफी बस, आप या तो अपडेट () कॉल का उपयोग करते हैं, या, आप एक coroutine का उपयोग करते हैं। (वास्तव में - वे वास्तव में एक ही चीज हैं: वे कोड को हर फ्रेम चलाने की अनुमति देते हैं।)

एक coroutine का उद्देश्य यह है कि:

आप कुछ कोड चला सकते हैं, और फिर, कुछ भविष्य के फ्रेम तक "रोकें और प्रतीक्षा करें"।

आप अगले फ्रेम तक इंतजार कर सकते हैं, आप कई फ्रेम का इंतजार कर सकते हैं, या आप भविष्य में सेकंड में कुछ अनुमानित समय का इंतजार कर सकते हैं।

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

एक coroutine के अंदर:

एक फ्रेम की प्रतीक्षा करने के लिए:

// do something
yield return null;  // wait until next frame
// do something

तीन फ्रेम प्रतीक्षा करने के लिए:

// do something
yield return null;  // wait until three frames from now
yield return null;
yield return null;
// do something

लगभग आधा सेकंड इंतजार करने के लिए:

// do something
yield return new WaitForSeconds (0.5f); // wait for a frame in about .5 seconds
// do something

हर एक फ्रेम में कुछ करें:

while (true)
{
    // do something
    yield return null;  // wait until the next frame
}

यह उदाहरण शाब्दिक रूप से एकता के "अपडेट" कॉल के अंदर कुछ डालने के लिए समान है: प्रत्येक फ्रेम में "कुछ करें" कोड को चलाया जाता है।

उदाहरण

टिकर को GameObject अटैच करें। जबकि वह गेम ऑब्जेक्ट सक्रिय है, टिक टिक जाएगा। ध्यान दें कि जब खेल ऑब्जेक्ट निष्क्रिय हो जाता है, तो स्क्रिप्ट सावधानीपूर्वक कोरटाइन को रोक देती है; यह आमतौर पर सही ढंग से इंजीनियरिंग कोरटाइन उपयोग का एक महत्वपूर्ण पहलू है।

using UnityEngine;
using System.Collections;

public class Ticker:MonoBehaviour {

    void OnEnable()
    {
        StartCoroutine(TickEverySecond());
    }

    void OnDisable()
    {
        StopAllCoroutines();
    }

    IEnumerator TickEverySecond()
    {
        var wait = new WaitForSeconds(1f); // REMEMBER: IT IS ONLY APPROXIMATE
        while(true)
        {
            Debug.Log("Tick");
            yield return wait;  // wait for a frame, about 1 second from now
        }
    }
}

एक coroutine समाप्त करना

अक्सर आप कुछ लक्ष्यों को पूरा करने के लिए स्वाभाविक रूप से समाप्त होने के लिए कोरटाइन डिजाइन करते हैं।

IEnumerator TickFiveSeconds()
{
    var wait = new WaitForSeconds(1f);
    int counter = 1;
    while(counter < 5)
    {
        Debug.Log("Tick");
        counter++;
        yield return wait;
    }
    Debug.Log("I am done ticking");
}

कोरटाइन को "अंदर" से बंद करने के लिए, आप एक साधारण फ़ंक्शन से जल्दी निकलने के लिए बस "वापसी" नहीं कर सकते। इसके बजाय, आप yield break उपयोग करें।

IEnumerator ShowExplosions()
{
    ... show basic explosions
    if(player.xp < 100) yield break;
    ... show fancy explosions
}

आप परिष्करण से पहले रुकने के लिए स्क्रिप्ट द्वारा लॉन्च किए गए सभी कोरआउट्स को भी बाध्य कर सकते हैं।

void OnDisable()
{
    // Stops all running coroutines
    StopAllCoroutines();
}

कॉलर से किसी विशिष्ट कॉरआउट को रोकने की विधि इस बात पर निर्भर करती है कि आपने इसे कैसे शुरू किया।

यदि आपने स्ट्रिंग नाम से एक coroutine शुरू किया है:

StartCoroutine("YourAnimation");

तो आप इसे उसी स्ट्रिंग नाम से StopCoroutine कहकर रोक सकते हैं:

StopCoroutine("YourAnimation");

वैकल्पिक रूप से, आप के लिए या तो एक संदर्भ रख सकते IEnumerator coroutine विधि, या द्वारा दिया Coroutine वस्तु द्वारा दिया StartCoroutine , और कॉल StopCoroutine उन दोनों में से किसी पर:

public class SomeComponent : MonoBehaviour 
{
    Coroutine routine;

    void Start () {
        routine = StartCoroutine(YourAnimation());
    }

    void Update () {
        // later, in response to some input...
        StopCoroutine(routine);
    }

    IEnumerator YourAnimation () { /* ... */ }
}

MonoBehaviour विधियाँ जो कि Coroutines हो सकती हैं

तीन मोनोहेवियर तरीके हैं जिन्हें कोरटाइन बनाया जा सकता है।

  1. शुरू()
  2. OnBecameVisible ()
  3. OnLevelWasLoaded ()

इसका उपयोग बनाने के लिए किया जा सकता है, उदाहरण के लिए, स्क्रिप्ट जो केवल तब निष्पादित होती है जब ऑब्जेक्ट किसी कैमरे को दिखाई देता है।

using UnityEngine;
using System.Collections;

public class RotateObject : MonoBehaviour
{
    IEnumerator OnBecameVisible()
    {
        var tr = GetComponent<Transform>();
        while (true)
        {
            tr.Rotate(new Vector3(0, 180f * Time.deltaTime));
            yield return null;
        }
    }
    
    void OnBecameInvisible()
    {
        StopAllCoroutines();
    }
}

कोरटन का पीछा करना

Coroutines खुद के अंदर उपज सकता है, और अन्य coroutines की प्रतीक्षा कर सकता है।

तो, आप श्रृंखला अनुक्रम कर सकते हैं - "एक के बाद एक"।

यह बहुत आसान है, और एकता में एक बुनियादी, मूल, तकनीक है।

यह खेल में बिल्कुल स्वाभाविक है कि कुछ चीजें "क्रम में" होती हैं। खेल का लगभग हर "दौर" कुछ क्रमों में, समय की एक जगह पर होने वाली घटनाओं की एक निश्चित श्रृंखला के साथ शुरू होता है। यहां बताया गया है कि आप कार रेस गेम कैसे शुरू कर सकते हैं:

IEnumerator BeginRace()
{
  yield return StartCoroutine(PrepareRace());
  yield return StartCoroutine(Countdown());
  yield return StartCoroutine(StartRace());
}

तो, जब आप BeginRace कहते हैं ...

 StartCoroutine(BeginRace());

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

स्पष्टता के लिए, समझें कि तीन कॉल

  yield return StartCoroutine(PrepareRace());
  yield return StartCoroutine(Countdown());
  yield return StartCoroutine(StartRace());

खुद को एक कोरटाइन में होना चाहिए। यह कहना है, वे IEnumerator प्रकार के एक समारोह में होना चाहिए। तो हमारे उदाहरण में IEnumerator BeginRace । तो, "सामान्य" कोड से, आप उस StartCoroutine को StartCoroutine कॉल के साथ लॉन्च करते हैं।

 StartCoroutine(BeginRace());

चेनिंग को और समझने के लिए, यहां एक फ़ंक्शन है जो कोरटाइन को जंजीर देता है। आप कोरआउट की एक सरणी में पास करते हैं। आप एक के बाद एक, जितने पास से गुजरते हैं, फंक्शन उतने ही कोरटाइन्स से चलता है।

// run various routines, one after the other
IEnumerator OneAfterTheOther( params IEnumerator[] routines ) 
{
    foreach ( var item in routines ) 
    {
        while ( item.MoveNext() ) yield return item.Current;
    }

    yield break;
}

यहां बताया गया है कि आप कैसे कॉल करेंगे ... मान लीजिए कि आपके तीन कार्य हैं। याद रखें कि वे सभी IEnumerator होना चाहिए:

IEnumerator PrepareRace() 
{
    // codesay, crowd cheering and camera pan around the stadium
    yield break;
}

IEnumerator Countdown() 
{
    // codesay, animate your countdown on UI
    yield break;
}

IEnumerator StartRace() 
{
    // codesay, camera moves and light changes and launch the AIs
    yield break;
}

आप इसे इस तरह कहेंगे

StartCoroutine( MultipleRoutines( PrepareRace(), Countdown(), StartRace() ) );

या शायद इस तरह

IEnumerator[] routines = new IEnumerator[] {
     PrepareRace(),
     Countdown(),
     StartRace() };
StartCoroutine( MultipleRoutines( routines ) );

दोहराने के लिए, खेलों में सबसे बुनियादी आवश्यकताओं में से एक यह है कि कुछ चीजें एक के बाद एक "अनुक्रम में" समय के साथ होती हैं। आप एकता को बहुत ही सरलता से हासिल करते हैं

  yield return StartCoroutine(PrepareRace());
  yield return StartCoroutine(Countdown());
  yield return StartCoroutine(StartRace());

उपज देने के तरीके

आप अगले फ्रेम तक इंतजार कर सकते हैं।

yield return null; // wait until sometime in the next frame

आप इनमें से कई कॉल एक पंक्ति में कर सकते हैं, बस वांछित के रूप में कई फ्रेम के लिए प्रतीक्षा करें।

//wait for a few frames
yield return null;
yield return null;

लगभग n सेकंड के लिए प्रतीक्षा करें। यह समझना बहुत महत्वपूर्ण है यह केवल एक बहुत ही अनुमानित समय है

yield return new WaitForSeconds(n);

किसी भी रूप में सटीक समय के लिए "WaitForSeconds" कॉल का उपयोग करना बिल्कुल संभव नहीं है।

अक्सर आप क्रियाओं को श्रृंखलाबद्ध करना चाहते हैं। इसलिए, कुछ करो, और जब समाप्त हो जाए तो कुछ और करो, और जब समाप्त हो जाए तो कुछ और करो। इसे प्राप्त करने के लिए, किसी अन्य कोरआउट के लिए प्रतीक्षा करें:

yield return StartCoroutine(coroutine);

समझें कि आप केवल एक कॉरटीन के भीतर से ही कॉल कर सकते हैं। इसलिए:

StartCoroutine(Test());

इस तरह से आप कोड के "सामान्य" टुकड़े से एक कोरआउट शुरू करते हैं।

फिर, अंदर चल रहा है कि coroutine:

Debug.Log("A");
StartCoroutine(LongProcess());
Debug.Log("B");

वह A प्रिंट करेगा, लंबी प्रक्रिया शुरू करेगा, और तुरंत B प्रिंट करेगा । यह लंबी प्रक्रिया खत्म होने का इंतजार नहीं करेगा। दूसरी ओर:

Debug.Log("A");
yield return StartCoroutine(LongProcess());
Debug.Log("B");

कि ए को प्रिंट करेगा, लंबी प्रक्रिया शुरू करेगा, समाप्त होने तक प्रतीक्षा करेगा और फिर बी प्रिंट करेगा।

यह हमेशा याद रखने योग्य है कि कोराउटीन का थ्रेडिंग करने के लिए किसी भी तरह से कोई संबंध नहीं है। इस कोड के साथ:

Debug.Log("A");
StartCoroutine(LongProcess());
Debug.Log("B");

पृष्ठभूमि में दूसरे धागे पर लॉन्गप्रोसेस को शुरू करना "पसंद" होने के रूप में इसके बारे में सोचना आसान है। लेकिन यह बिल्कुल गलत है। यह सिर्फ एक कोरटाइन है। गेम इंजन फ़्रेम आधारित हैं, और एकता में "कोराउटाइन" बस आपको फ़्रेम तक पहुंचने की अनुमति देते हैं।

वेब अनुरोध को पूरा करने के लिए इंतजार करना बहुत आसान है।

void Start() {
    string url = "http://google.com";
    WWW www = new WWW(url);
    StartCoroutine(WaitForRequest(www));
}

IEnumerator WaitForRequest(WWW www) {
    yield return www;
    
    if (www.error == null) {
        //use www.data);
    }
    else {
        //use www.error);
    }
}

पूर्णता के लिए: बहुत कम मामलों में आप एकता में निश्चित अद्यतन का उपयोग करते हैं; एक WaitForFixedUpdate() कॉल है जो सामान्य रूप से कभी भी उपयोग नहीं किया जाएगा। एक विशिष्ट कॉल ( WaitForEndOfFrame() एकता के वर्तमान संस्करण में) है जो विकास के दौरान स्क्रीन कैप्चर उत्पन्न करने के संबंध में कुछ स्थितियों में उपयोग किया जाता है। (सटीक तंत्र थोड़ा विकसित होता है क्योंकि एकता विकसित होती है, इसलिए प्रासंगिक होने पर नवीनतम जानकारी के लिए Google।)



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow