因为有延时又出错了,所以这次查了下协同程序大部分是搜索
百度知道里
协同程序(coroutine)与多线程情况下的线程比较类似:有自己的堆栈,自己的局部变量,有自己的指令指针([url=]IP[/url],instruction pointer),但与其它协同程序共享全局变量等很多信息。线程和协同程序的主要不同在于:在多处理器情况下,从概念上来讲多线程程序同时运行多个线程;而协同程序是通过协作来完成,在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只在必要时才会被挂起。//===============================================================================================================================而在Unity中,我们自然也可以使用这种方法来进行延时,但是相对而言,这种方法并不是最佳实践,更好的在Unity中实现延时的做法是使用Coroutine,就代码上来看的话,大概是这个样子:
IEnumerator DelayCoroutine() {
// work before delay
yield return new WaitForSeconds(<time value to delay>);
// work after delay
}
StartCoroutine(DelayCoroutine());//===============================================================================================================================当然我也是,不过我错了Assets/scripts/playerstateController.cs(148,14): error CS1624: The body of `playerstateController.OnTriggerEnter(UnityEngine.Collider)' cannot be an iterator block because `void' is not an iterator interface type
=================================================================================================================================
1.没有什么elapsedTime之类的变量,
甚至没有什么Update,你要做的就是写一个以IEnumerator为返回类型的方法,
然后在其中使用yield return这种语法来返回一个WaitForSeconds类型的实例,
实例的构造参数就是你想要延时的时间,然后在需要的时候,调用StartCoroutine来进行延时即可。
2.这Coroutine是什么?从字面意思上来理解,Coroutine应该就是“协程”的意思,而这所谓的“协程”又是什么东西?
3.这Unity“协程”跟线程又是一个什么关系,就其可以进行延时而不影响其他逻辑运行这个特性来看,“协程”是否就是C#线程的一个封装呢?
4.就是返回类型IEnumerator,名字奇怪了,我还需要使用yield return这种奇怪的方式来进行返回,
WaitForSeconds也并不是一个所谓IEnumerator的类型,怎么就可以正常返回呢?
5.虽然WaitForSeconds这个类型的名称意义一目了然,但就实现层面来看,其是如何做到延时这项功能的着实让人摸不着头脑
//=========================================================
地址:http://tieba.baidu.com/p/2912424135
//=========================================================
帖子解答
两个奇怪的IEnumerator和yield return,其实并不是Unity的什么独创,
相反,他们却是C#中到处可见的迭代器的构造方式(之一),
你也许对于迭代器这个东西没什么印象,但实际上,我们可能天天都在使用它!让我们马上来看一个最普遍的迭代器运用:
int[] array = new int[] {1, 2, 3, 4, 5};
foreach (int val in array) {
// do something
}
代码非常简单,不过是使用foreach来遍历一个整型数组,
而代码中我们早已习以为常的foreach其实就是迭代器的语法糖,在真正的运行代码中,C#的编译器会将上面的代码改头换面成这个样子:
int[] array = new int[] {1, 2, 3, 4, 5};
IEnumerator e = array.GetEnumerator();
while (e.MoveNext()) {
// do something
}
上述代码首先通过array的GetEnumerator方法
来获取array的一个“迭代器”,然后通过“迭代器”的MoveNext方法进行依次遍历,
而这“迭代器”实际上就是之前那个稍显奇怪的IEnumerator类型!
而至于yield return,其实是C# 2.0新引进的一种实现迭代器模式的简便语法,在之前的C# 1.0中,
如果要实现一个完整的迭代器,我们必须要分别实现IEnumerable和IEnumerator这两个接口,
过程略显枯燥繁琐,而借助yield return,这两个步骤我们都可以省略!
//====================================================================================================
然后我又去百度了下IEnumerable和IEnumerator这两个接口是什么,为什么要实现?
IEnumerable接口和IEnumerator接口是.NET中非常重要的接口,二者有何区别? 1. 简单来说IEnumerable是一个声明式的接口,声明实现该接口的类就是“可迭代的enumerable”,但并没用说明如何实现迭代器(iterator).其代码实现为: public interface IEnumerable
{
IEnumerator GetEnumerator();
}
2. 而IEnumerator接口是实现式接口,它声明实现该接口的类就可以作为一个迭代器iterator.其代码实现为: public interface IEnumerator
{
object Current { get; } bool MoveNext();
void Reset();
}
//=====================================================================================================
迭代器是什么?
迭代器(iterator)有时又称游标(cursor)是程序设计的[url=]软件设计模式[/url],可在容器(container,例如[url=]链表[/url]或[url=]阵列[/url])上遍访的接口,设计人员无需关心容器的内容。
迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。迭代器修改了常规[url=]指针[/url]的接口,所谓迭代器是一种概念上的抽象:那些行为上像迭代器的东西都可以叫做迭代器。然而迭代器有很多不同的能力,它可以把抽象容器和通用算法有机的统一起来。
迭代器提供一些基本操作符:*、++、==、!=、=。这些操作和C/C++“操作array元素”时的指针接口一致。不同之处在于,迭代器是个所谓的复杂的指针,具有遍历复杂数据结构的能力。其下层运行机制取决于其所遍历的数据结构。因此,每一种容器型别都必须提供自己的迭代器。事实上每一种容器都将其迭代器以嵌套的方式定义于内部。因此各种迭代器的接口相同,型号却不同。这直接导出了[url=]泛型[/url]程序设计的概念:所有操作行为都使用相同接口,虽然它们的型别不同。
功能迭代器使开发人员能够在类或结构中支持foreach迭代,而不必整个实现IEnumerable或者IEnumerator接口。只需提供一个迭代器,即可遍历类中的数据结构。当[url=]编译器[/url]检测到迭代器时,将自动生成IEnumerable接口或者IEnumerator接口的Current,MoveNext和Dispose方法
//==========================================================================================================================
再回来:
Unity其实是使用了迭代器来实现延时的,像IEnumerator、yield return等的使用皆是为了配合C#中迭代器的语法,其与什么多线程之类的概念并没有多少关系,但是目前我仍然还是不能理解之前的那个最大疑问:虽然迭代器可以保留运行状态以便下次继续往下运行,
!!!!=但是他本身并没有提供什么机制来达到延时之类的效果,像foreach这种语句,虽然使用了迭代器,但实际上也是一股脑儿运行完毕的,并不存在延时一说,那么在Unity中,为什么简单的返回一个WaitForSeconds就可以呢?!!!!!!
//===========================================================================================================================
看来答案应该是在WaitForSeconds这个类型身上了~经过简单的一些搜索,我找到了这么一篇帖子,内容便是如何自己实现一个简单的WaitForSeconds,大体上的思路便是使用循环yield return null这种方法来达到延时的目的,直接抄一段帖子中的示例代码:
using UnityEngine;
using System.Collections;
public class TimerTest : MonoBehaviour {
IEnumerator Start () {
yield return StartCoroutine(MyWaitFunction (1.0f));
print ("1");
yield return StartCoroutine(MyWaitFunction (2.0f));
print ("2");
}
IEnumerator MyWaitFunction (float delay) {
float timer = Time.time + delay;
while (Time.time < timer) {
yield return null;
}
}
}
我自己这里不知道能不能理解为对循环的多次套用?MyWaitFunction 是大循环,大循环下包含着迭代?
//================================================================================================
后面的这部分看得我云里雾里QAQ
//===============================================================================================
而完成这些操作的,很可能便是WaitForSeconds的构造函数,因为每次延时我们都就地生成(new)了一个WaitForSeconds实例。
然而使用ILSpy查看WaitForSeconds实现源码的结果却又让我迷惑:WaitForSeconds的构造函数非常简单,似乎仅是记录一个时间变量罢了,根本就不存在什么While、yield之类的东西,而其父类YieldInstruction则更简单,就是单纯的一个空类……另外的,WWW这个Unity内建类型的使用方式也同样让我不解:
using UnityEngine;
using System.Collections;
public class Example : MonoBehaviour {
public string url = "[url=]http://www.baidu.com/logo.gif[/url]";
IEnumerator Start() {
WWW www = new WWW(url);
yield return www;
renderer.material.mainTexture = [url=]www.texture;[/url]
}
}
在上面的示例代码中,yield return www;这条语句可以做到直到url对应资源下载完毕才继续往下运行(迭代),效果上类似于WaitForSeconds,但是WWW本身却又不像WaitForSeconds那样是个YieldInstruction,而且在使用上也是首先创建实例,然后直接yield 返回引用,按照这种做法,即便WWW的构造函数使用了上面的那种循环yield return null的方法,实际上也达不到我们想要的等待效果;
再者便是语法上的一些细节,首先如果我们需要使用yield return的话,返回类型就必须是IEnumerable(<T>)或者IEnumerator(<T>)之一,而C#中的构造函数是没有返回值的,显然不符合这个原则,所以实际上在构造函数中我们无法使用什么yield return,另外的一点,虽然上述帖子中的方法可以实现自己的延时操作,但每次都必须进行StartCoroutine操作(如果没有也起不到延时效果),这一点也与一般的WaitForSeconds使用存在差异……
后来看到了这篇文章,才大抵让我有所释怀:之前自己的种种猜测都聚焦在类似WaitForSeconds这些个特殊类型之上,一直以为这些类型肯定存在某些个猫腻,但实际上,这些类型(WaitForSeconds、WWW之类)都是“非常正常”的类型,并没有什么与众不同之处,而让他们显得与众不同的,其实是StartCoroutine这个我过去一直忽略的家伙!(哈,不知道——)
//==============================================================================================================
原理其实很简单,WaitForSeconds本身是一个普通的类型,但是在StartCoroutine中,其被特殊对待了,一般而言,StartCoroutine就是简单的对某个IEnumerator 进行MoveNext()操作,但如果他发现IEnumerator其实是一个WaitForSeconds类型的话,那么他就会进行特殊等待,一直等到WaitForSeconds延时结束了,才进行正常的MoveNext调用,而至于WWW或者WaitForFixedUpdate等类型,StartCoroutine也是同样的特殊处理,如果用代码表示一下的
//==========================================================================================================================================
后面就不怎么懂了,原主自己写了一个延时,等我在了解下unity和c#再滚回来再看看比较好
|