2010-08-09 88 views
10

我得到了这个方法(在Unity C#脚本中),但我不明白“yield”部分是如何工作的。具有“yield”功能的这个功能是如何工作的?

我知道从M​​SDN该函数将返回一个IEnumerator,我可以迭代通过,但此代码等待1.5秒,并没有得到迭代,因为这意味着,内部创建的对象创建多次。 任何人都可以向我解释这段代码的工作原理吗?

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

问题标题可能更具描述性。不过,Google仍然拿起关键字。 – ftvs 2012-11-28 11:26:34

回答

21

编译器为您的枚举被重复。一旦。

编译器将生成一个实现IEnumerator的类,该类具有MoveNext()函数和Current属性。该类将具有所有需要在调用之间存储函数状态的成员。具体细节可以被认为是“编译魔术师”。

此生成的类的对象将由Unity3d引擎处理和管理。 Unity3d引擎会在每个帧的每个活动协程上调用MoveNext()(除非另有说明)。

这使得Unity3d程序员可以编写一次一帧地播放的脚本。 C#编译器魔术和Unity3d引擎魔术的结合产生了非常强大但易于使用的脚本。

要回答你的问题:函数中的代码将被执行一次,但会在'yield return'语句中暂停。

如上所述,实现IEnumerator的特殊对象由C#编译器创建。

第一次调用MoveNext()时,函数会创建一个爆炸并将当前对象设置为“new WaitForSeconds(1.5f)”。

Unity3d引擎检查此对象,发现它是特殊类“WaitForSeconds”的一个实例,因此将枚举器置于某个等待队列中,直到1.5秒后才会请求第二个元素。与此同时,许多帧将被渲染,爆炸将被播放。

1.5秒后,Unity将从队列中抓取枚举数,并再次调用MoveNext()。函数的第二部分将立即执行,但不会生成第二个对象。 MoveNext()会返回false来表明它没有得到一个新的元素,这是Unity3d抛出这个枚举器的信号。垃圾收集器将在某个时间点回收内存。

如上所述:大量的编译器和Unity3d魔法正在进行中。只要你记得你的函数将被搁置,直到每个yield return语句的下一帧,你就会知道有足够的好处从这些特殊函数中受益。

+0

在独立的c#项目中编写代码,并在ILSPy中查看生成的.net程序集,可以快速掌握所有魔法的工作原理。 – 2012-01-02 21:35:21

5

如果yield使用一次,这是因为如果你用一个元素返回一个IEnumerator,这就是为什么你得到的印象是,它不会重复。

这是yield关键字的一个相当奇怪的用法,很难理解为什么它没有看到整个上下文而被实现。

+1

它被称为“StartCoroutine”的函数调用:Unity.StartCoroutine(DestroyShip),我认为这是非常具体的Unity编程http://unity3d.com – 2010-08-09 09:28:11

+0

参考:http://unity3d.com/support/documentation /ScriptReference/MonoBehaviour.StartCoroutine.html – 2010-08-09 09:29:51

+1

我看到......好吧,这在Unity引擎的环境中确实很有意义。 – 2010-08-09 09:35:06

1

最好是退还IEnumerable而不是IEnumerator,因为它比较灵活,易于使用。它更好使用IEnumerable<T>。 Yield return只是用于实现迭代器块的语法糖,编译器会生成相关的代码,因为它本质上是标准的锅炉板,可以通过编程方式轻松生成。您通常使用收益回报时要进行一系列单一的行动apear是一个集合,例如:

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

除了Unity3d引擎是唯一使用IEnumerator的引擎,并且该引擎要求它是IEnumerable。人们可以争辩说,IEnumrable 更好,但也必须与Unity3d的设计desissions一起玩。 – Sjoerd 2010-08-09 09:33:26