2010-08-09 6 views
10

J'ai obtenu cette méthode (à l'intérieur d'un script Unity C#), mais je ne comprends pas comment fonctionne la partie "yield". Je sais par le MSDN que la fonction retournera un IEnumerator que je pourrais parcourir, mais ce code attend 1,5 secondes et ne sera pas itéré car cela signifierait que les objets créés à l'intérieur ont été créés plusieurs fois. Toute personne ici qui peut m'expliquer comment fonctionne ce code?Comment fonctionne cette fonction avec un "rendement" en détail?

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

Le titre de la question pourrait être plus descriptif. D'une certaine manière, Google a encore ramassé les mots-clés, cependant. – ftvs

Répondre

21

Le recenseur le compilateur génère pour vous est réitérée. Une fois que.

Le compilateur génère une classe qui implémente IEnumerator, qui possède une fonction MoveNext() et une propriété Current. La classe aura tous les membres requis pour stocker l'état de la fonction entre les appels. Les détails exacts peuvent être considérés comme "Magie du compilateur".

L'objet de cette classe générée sera géré et géré par le moteur Unity3d. Le moteur Unity3d appellera MoveNext() sur chaque coroutine active une fois par trame (sauf indication contraire).

Cela a permis au programmeur Unity3d d'écrire des scripts qui sont lus une image à la fois. Une combinaison de la magie du compilateur C# et de la magie du moteur Unity3d aboutit à des scripts très puissants mais faciles à utiliser.

Pour répondre à votre question: le code de votre fonction sera exécuté une fois, mais il sera mis en pause à l'instruction 'return return'.

Comme indiqué ci-dessus, un objet spécial qui implémente IEnumerator est créé par le compilateur C#. Lors du premier appel à MoveNext(), votre fonction crée une explosion et définit l'objet en cours sur "new WaitForSeconds (1.5f)". Le moteur Unity3d inspecte cet objet, voit qu'il s'agit d'une instance de la classe spéciale "WaitForSeconds", met donc l'énumérateur sur une file d'attente et ne demandera pas le second élément avant que 1,5 sec soit passé. En attendant, beaucoup de cadres seront rendus et l'explosion sera jouée. Au bout de 1,5 seconde, Unity récupère l'énumérateur dans la file d'attente et appelle à nouveau MoveNext(). La deuxième partie de votre fonction s'exécutera maintenant, mais ne pourra pas générer un second objet. MoveNext() retournera false pour indiquer qu'il n'a pas réussi à obtenir un nouvel élément, ce qui est le signal à Unity3d pour l'éloigner de cet énumérateur. Le Garbage Collector récupérera la mémoire à un moment donné.Comme dit: beaucoup de compilateur et de magie Unity3d est en cours. Tant que vous vous souvenez que votre fonction sera mise en attente jusqu'à la prochaine image à chaque relevé de rendement, vous en saurez assez pour bénéficier de ces fonctions spéciales.

+0

L'écriture de ce code dans un projet C# autonome et l'examen de l'assembly .net généré dans ILSPy permettent de voir rapidement comment fonctionne la magie. –

5

Si yield est utilisé une fois, il est comme si vous reveniez un IEnumerator avec un élément, c'est la raison pour laquelle on a l'impression qu'il n'itérer pas.

C'est une utilisation plutôt étrange du mot-clé yield, il est difficile de comprendre pourquoi il a été implémenté sans voir tout le contexte.

+1

Il est appelé dans une fonction appelée "StartCoroutine": Unity.StartCoroutine (DestroyShip), je pense que cela est très spécifique à Unity Engine http://unity3d.com –

+0

Référence: http://unity3d.com/support/documentation /ScriptReference/MonoBehaviour.StartCoroutine.html –

+1

Je vois ... eh bien, cela a certainement du sens dans le contexte du moteur Unity. –

1

Il est préférable de retourner IEnumerable plutôt que IEnumerator car il est plus flexible et facile à utiliser. Il est même préférable d'utiliser IEnumerable<T>. Le rendement de rendement est juste du sucre syntaxique pour l'implémentation d'un bloc d'itérateur, le compilateur génère le code correspondant car il s'agit essentiellement d'une plaque de chaudière standard qui peut être générée facilement par programmation. Vous utilisez généralement le retour de rendement lorsque vous souhaitez effectuer une série d'actions individuelles apear être une collection, .: par exemple

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

Sauf que le moteur Unity3d est le seul à utiliser ce IEnumerator, et que ce moteur requiert un IEnumerable. On peut argumenter que IEnumrable est meilleur, mais on doit aussi jouer avec les desions de conception faites par Unity3d. – Sjoerd

Questions connexes