2010-08-09 20 views
10

Mam tę metodę (wewnątrz skryptu Unity C#), ale nie rozumiem, w jaki sposób część "wydajność" faktycznie działa.Jak to działa z "wydajnością" w szczegółach?

Wiem z MSDN, że funkcja zwróci IEnumerator, który mógłbym iterować, ale ten kod czeka 1,5 sekundy i nie jest iterowany, ponieważ oznaczałoby to, że obiekty utworzone wewnątrz zostały utworzone wiele razy. Ktoś tutaj może mi wyjaśnić, jak działa ten kod?

IEnumerator DestroyShip() 
{ 
    // create new gameobject 
    Instantiate(ExplosionPrefab, transform.position, transform.rotation); 
    // make current gameobject invisible 
    gameObject.renderer.enabled = false; 
    // set new position for the current gameobject 
    transform.position = new Vector3(0f, transform.position.y, transform.position.z); 
    // wait for 1,5 seconds 
    yield return new WaitForSeconds(1.5f); 
    // make the current gameobject visible again 
    gameObject.renderer.enabled = true; 
} 
+0

Tytuł pytania może być bardziej opisowy. W jakiś sposób Google jednak wychwyciło słowa kluczowe. – ftvs

Odpowiedz

21

numeratora kompilator generuje dla ciebie jest powtórzyć. Pewnego razu.

Kompilator wygeneruje klasę, która implementuje IEnumerator, który ma funkcję MoveNext() i właściwość Current. Klasa będzie miała wszystkich członków wymaganych do przechowywania stanu funkcji między połączeniami. Dokładne szczegóły można uznać za "Magię kompilatora".

Obiekt tej wygenerowanej klasy będzie obsługiwany i zarządzany przez silnik Unity3d. Silnik Unity3d wywoła funkcję MoveNext() na każdym aktywnym coroutine po każdej klatce (chyba że instrukcja jest inna).

Umożliwiło to programowi Unity3d napisanie skryptów odtwarzanych po jednej klatce na raz. Kombinacja magii kompilatora C# i magii silnika Unity3d zapewnia bardzo wydajne, ale łatwe w użyciu skrypty.

Aby odpowiedzieć na twoje pytanie: kod w twojej funkcji zostanie wykonany jeden raz, ale zostanie zatrzymany na wyciągu zwrotu.

Jak wspomniano powyżej, specjalny obiekt, który implementuje IEnumerator, jest tworzony przez kompilator C#.

Przy pierwszym wywołaniu funkcji MoveNext() funkcja powoduje eksplozję i ustawia bieżący obiekt na "nowy WaitForSeconds (1.5f)".

Silnik Unity3d kontroluje ten obiekt, widzi, że jest to instancja klasy specjalnej "WaitForSeconds", więc umieszcza moduł wyliczający w kolejce oczekujących i nie prosi o drugi element, dopóki nie minie 1,5 sekundy. W międzyczasie zostanie wyświetlonych wiele klatek, a eksplozja zostanie odtworzona.

Po 1,5 s, Unity wyrwie moduł wyliczający z kolejki i ponownie wywoła funkcję MoveNext(). Druga część twojej funkcji zostanie teraz uruchomiona, ale nie uda jej się wygenerować drugiego obiektu. Funkcja MoveNext() zwróci wartość false, aby wskazać, że nie udało się uzyskać nowego elementu, co jest sygnałem Unity3d, aby odrzucić ten moduł wyliczający. Garbage Collector odzyska pamięć w pewnym momencie.

Jak już powiedziano: dzieje się dużo kompilacji i magii Unity3d. Dopóki pamiętasz, że twoja funkcja zostanie wstrzymana do następnej klatki po każdym oświadczeniu o zwrocie plonów, będziesz wiedział wystarczająco dużo, aby skorzystać z tych specjalnych funkcji.

+0

Zapisanie tego kodu w samodzielnym projekcie C# i spojrzenie na wygenerowany zestaw .net w ILSPy jest szybkim okiem na temat działania wszystkich magii. –

5

yield Jeśli jest używany raz, to tak, jakbyś zwrócenie IEnumerator z jednego elementu, dlatego można odnieść wrażenie, że nie iterację.

To dość dziwne użycie słowa kluczowego yield, dlatego trudno jest zrozumieć, dlaczego zostało ono zaimplementowane, nie widząc całego kontekstu.

+1

Jest wywoływana w funkcji o nazwie "StartCoroutine": Unity.StartCoroutine (DestroyShip), myślę, że jest to bardzo specyficzne dla Unity Engine http://unity3d.com –

+0

Odniesienia: http://unity3d.com/support/documentation /ScriptReference/MonoBehaviour.StartCoroutine.html –

+1

Widzę ... cóż, z pewnością ma to sens w kontekście silnika Unity. –

1

Lepiej jest zwrócić IEnumerable niż IEnumerator, ponieważ jest bardziej leniwy i łatwy w użyciu. Jeszcze lepiej jest użyć IEnumerable<T>. Powrót plonu jest po prostu cukrem syntaktycznym do wykonania bloku iteratora, kompilator generuje kod relevent, ponieważ jest to w zasadzie standardowa płyta kotła, którą można łatwo wygenerować programowo. Zazwyczaj użyć zwrotu plastyczności, gdy chcesz zrobić serię pojedynczych działań apear być zbiorem, np .:

public IEnumerable<Thing> GetThings() 
{ 
    yield return GetNextThing(); 
} 
+1

Z tym, że silnik Unity3d jest jedynym, który używa tego IEnumeratora, a ten silnik wymaga, aby był IEnumerable. Można argumentować, że IEnumrable jest lepszy, ale trzeba też grać razem z desidacjami stworzonymi przez Unity3d. – Sjoerd