最近我看到了一个在Unity中使用C#生成对象的教程。
public IEnumerator CallSpawner()
{
yield return new WaitForSeconds(0.5f);
SpawnObstacles();
}
我想问一下IEnumerator函数有什么用,我们不能通过这个过程来实现吗
float diffTime = 0f;
private void Update()
{
if(Time.time - diffTime == 0.5f)
{
diffTime = Time.time;
SpawnObstacles();
}
}
我读了文档,但无法理解它。
3条答案
按热度按时间e4eetjau1#
IEnumerator函数的用途是什么
IEnumerator
没有函数,它是一个 * 返回类型 *。C#也没有函数(但我知道你的意思)-在C#中我们称它们为 * 方法 *。IEnumerator是一个接口,所以任何实现了IEnumerator接口的类都可以通过这个方法返回
在实践中,在这种使用中,它看起来实际上更像是一种黑客,而不是打算提供枚举器的真正意图,即一步一步地步枪通过(或生成)一个事物的集合。
当你在一个方法中使用一个
yield return
语句时,“一些神奇的事情发生了”,它不是一个经典意义上的return
,而是创建了一个工具,代码可以从它停止的地方恢复(从返回的枚举器中调用下一个项将导致代码从yield之后恢复,使用它之前的所有状态,而不是重新开始)。如果你看一下MSDN的yield示例:
环路由
i
控制;如果这不是一个yield return
,那么这将不会像预期的那样运行(它不能返回一个枚举数作为开始,但我们将忽略它)。代码将进入,开始循环,命中return
,并只返回一个数字一次,所有的内存中的循环将被遗忘。通过将其设置为
yield return
,将返回一个枚举数,并设置一个小的“保存状态”集,从而使循环可以记住i
的当前值每次请求下一个值时,代码将从中断处继续执行。(即刚屈服后)循环再次循环,并产生不同的值。2这继续到最大值。此时返回的枚举数表示它没有更多的项你也可以永远地产生……如果代码永远不能逃脱循环,那么它将永远地产生/生成
在这种情况下,你必须使用
yield return new WaitForSeconds
,因为这就是WaitForSeconds的工作方式。Yielding将枚举器交给调用方法,然后调用方法可以自由地枚举它。从文档来看,这似乎是故意在下一帧上完成的,所以利用收益率(可能重复)是一种安排代码块的方法,该代码块跨多个帧出现,而无需某种外部状态管理来记住过程是一个冗长的你可以
难道我们不能通过这个过程
当然,看起来很合理;每秒看100次时钟,如果从你第一次看时钟开始已经过了0.5秒,产生障碍
我会想象(从未使用过Unity;不要自称知道任何关于它的东西,除了读过这个函数的文档),你的更新循环有更多的事情要做,所以把一个进程交给一个专门的wait-then-do比花所有的时间看时钟和执行一个可能复杂的calc来计算你是否应该做某事更有效;生活中的大多数事情,一开始都是每隔x毫秒轮询一次,现在都可以从“如果事件发生,就做出React”的工作方式中受益
aydmsdu92#
您正在查看的代码仅存在于Unity3d和DotNet Framework〈4.0中。
你找不到任何相关文档的原因是:
1.这是一个邪恶的黑客(由Jeffrey Richter首创),它滥用了C#编译器的IEnumerable状态机生成器特性。
1.微软的家伙们早就把这个黑客添加到dot net编译器中了,他们把这个功能称为
async
/await
。不幸的是,Unity3d基于旧版本的Mono,它不支持
async
/await
。幸运的是,
async
/await
的大多数特性都可以使用这种方法来实现有几个理由支持Jeff的强力线程库方法。
1.您有一个方法来设置等待、定义等待时间和执行有效负载,并按此顺序执行。
1.性能。您建议的代码每秒将运行多次,当您轮询超时完成时会减慢系统速度。相反,PTL方法提供了一个回调事件,该事件将在将来调度。
1.清理。您的代码将继续运行,在
SpawnObstacles()
运行一次后检查0.5长。1.模糊计时。如果你的电脑由于延迟,性能等原因跳帧,你可能已经完全跳过了0.5帧。更重要的是,有可能,0.5d永远不会发生(请参阅Jon Skeet的Pony Fail帖子,你正在做一个双对双比较)。计时器/回调肯定会在0.5秒后的某个时间触发。
但主要的原因必须是心流。在这个非常简单的例子中,我们不会轻易混淆。然而,想象一下以下效果。
用
update
方法来写这段代码是相当困难的。但是,您可以轻松地使用IEnumerable。
作为奖励,您将注意到所有变量都很好地封装在Method中,而不是自由浮动的字段中。
这意味着您可以运行多个CallSpawner()而不会受到它们的干扰。
dauxcl2d3#
协程是一种编写代码的方法,它说“在队列中等待一会儿”。
更准确地说,WaitForSeconds和“wait until the next frame”(yield return null)是让代码在一个位置等待的命令。它们只能在协程内部使用。