unity unity setupcoroutinee是自动停止的吗

下次自动登录
现在的位置:
& 综合 & 正文
unity3d StopCoroutine 停止协同程序
function StopCoroutine (methodName : string) : void
Description描述
停止这个动作中名为methodName的所有协同程序。
请注意只有StartCoroutine使用一个字符串方法名时才能用StopCoroutine停用之.
// 这个例子演示如何调用一个使用字符串名称的协同程序并停掉它
function Start ()
StartCoroutine("DoSomething", 2.0);
StopCoroutine("DoSomething");
function DoSomething (someParameter : float)
while (true)
print("DoSomething Loop");
// 停止协同程序的执行并返回到主循环直到下一帧.
【上篇】【下篇】关于 Unity 的 coroutine 问题? - 知乎81被浏览<strong class="NumberBoard-itemValue" title="分享邀请回答111 条评论分享收藏感谢收起112 条评论分享收藏感谢收起Unity协程(Coroutine)原理深入剖析
我的图书馆
Unity协程(Coroutine)原理深入剖析
Unity协程(Coroutine)原理深入剖析
& By D.S.Qiu
尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com
& & & & 记得去年6月份刚开始实习的时候,当时要我写网络层的结构,用到了协程,当时有点懵,完全不知道Unity协程的执行机制是怎么样的,只是知道函数的返回值是IEnumerator类型,函数中使用yield return ,就可以通过StartCoroutine调用了。后来也是一直稀里糊涂地用,上网google些基本都是例子,很少能帮助深入理解Unity协程的原理的。
& & & & 本文只是从Unity的角度去分析理解协程的内部运行原理,而不是从C#底层的语法实现来介绍(后续有需要再进行介绍),一共分为三部分:
& & & & & & & & &&
线程(Thread)和协程(Coroutine)
& & & & & & & & & & & &&
Unity中协程的执行原理
& & & & & & & &
IEnumerator & Coroutine
& & & & 之前写过一篇《
》主要是介绍TaskManager实现对协程的状态控制,没有Unity后台实现的协程的原理进行深究。虽然之前自己对协程还算有点了解了,但是对Unity如何执行协程的还是一片空白,在UnityGems.com上看到两篇讲解Coroutine,如数家珍,当我看到Advanced Coroutine后面的Hijack类时,顿时觉得十分精巧,眼前一亮,遂动了写文分享之。
线程(Thread)和协程(Coroutine)
& & & & D.S.Qiu觉得使用协程的作用一共有两点:1)延时(等待)一段时间执行代码;2)等某个操作完成之后再执行后面的代码。总结起来就是一句话:控制代码在特定的时机执行。
& & & & 很多初学者,都会下意识地觉得协程是异步执行的,都会觉得协程是C# 线程的替代品,是Unity不使用线程的解决方案。
& & & & 所以首先,请你牢记:协程不是线程,也不是异步执行的。协程和 MonoBehaviour 的 Update函数一样也是在MainThread中执行的。使用协程你不用考虑同步和锁的问题。
Unity中协程的执行原理
& & & & UnityGems.com给出了协程的定义:
& & & & & & & &A coroutine is a function that is executed partially and, presuming suitable conditions are met, will be resumed at some point in the future until its work is done.
& & & & 即协程是一个分部执行,遇到条件(yield return 语句)会挂起,直到条件满足才会被唤醒继续执行后面的代码。
& & & & Unity在每一帧(Frame)都会去处理对象上的协程。Unity主要是在Update后去处理协程(检查协程的条件是否满足),但也有写特例:
& & & & 从上图的剖析就明白,协程跟Update()其实一样的,都是Unity每帧对会去处理的函数(如果有的话)。如果MonoBehaviour 是处于激活(active)状态的而且yield的条件满足,就会协程方法的后面代码。还可以发现:如果在一个对象的前期调用协程,协程会立即运行到第一个 yield return 语句处,如果是 yield return null ,就会在同一帧再次被唤醒。如果没有考虑这个细节就会出现一些奇怪的问题『1』。
& & & && 『1』注
图和结论都是从UnityGems.com 上得来的,经过下面的验证发现与实际不符,D.S.Qiu用的是Unity 4.3.4f1 进行测试的。 经过测试验证,协程至少是每帧的LateUpdate()后去运行。
& & & & 下面使用 yield return new WaitForSeconds(1f); 在Start,Update 和 LateUpdate 中分别进行测试:
using UnityE
using System.C
public class TestCoroutine : MonoBehaviour {
private bool isStartCall =
//Makesure Update() and LateUpdate() Log only once
private bool isUpdateCall =
private bool isLateUpdateCall =
// Use this for initialization
void Start () {
if (!isStartCall)
Debug.Log("Start Call Begin");
StartCoroutine(StartCoutine());
Debug.Log("Start Call End");
isStartCall =
IEnumerator StartCoutine()
Debug.Log("This is Start Coroutine Call Before");
yield return new WaitForSeconds(1f);
Debug.Log("This is Start Coroutine Call After");
// Update is called once per frame
void Update () {
if (!isUpdateCall)
Debug.Log("Update Call Begin");
StartCoroutine(UpdateCoutine());
Debug.Log("Update Call End");
isUpdateCall =
IEnumerator UpdateCoutine()
Debug.Log("This is Update Coroutine Call Before");
yield return new WaitForSeconds(1f);
Debug.Log("This is Update Coroutine Call After");
void LateUpdate()
if (!isLateUpdateCall)
Debug.Log("LateUpdate Call Begin");
StartCoroutine(LateCoutine());
Debug.Log("LateUpdate Call End");
isLateUpdateCall =
IEnumerator LateCoutine()
Debug.Log("This is Late Coroutine Call Before");
yield return new WaitForSeconds(1f);
Debug.Log("This is Late Coroutine Call After");
&得到日志输入结果如下:
& & & & 然后将yield return new WaitForSeconds(1f);改为 发现日志输入结果和上面是一样的,没有出现上面说的情况:
using UnityE
using System.C
public class TestCoroutine : MonoBehaviour {
private bool isStartCall =
//Makesure Update() and LateUpdate() Log only once
private bool isUpdateCall =
private bool isLateUpdateCall =
// Use this for initialization
void Start () {
if (!isStartCall)
Debug.Log("Start Call Begin");
StartCoroutine(StartCoutine());
Debug.Log("Start Call End");
isStartCall =
IEnumerator StartCoutine()
Debug.Log("This is Start Coroutine Call Before");
Debug.Log("This is Start Coroutine Call After");
// Update is called once per frame
void Update () {
if (!isUpdateCall)
Debug.Log("Update Call Begin");
StartCoroutine(UpdateCoutine());
Debug.Log("Update Call End");
isUpdateCall =
IEnumerator UpdateCoutine()
Debug.Log("This is Update Coroutine Call Before");
Debug.Log("This is Update Coroutine Call After");
void LateUpdate()
if (!isLateUpdateCall)
Debug.Log("LateUpdate Call Begin");
StartCoroutine(LateCoutine());
Debug.Log("LateUpdate Call End");
isLateUpdateCall =
IEnumerator LateCoutine()
Debug.Log("This is Late Coroutine Call Before");
Debug.Log("This is Late Coroutine Call After");
& & & & 前面在介绍TaskManager工具时,说到MonoBehaviour 没有针对特定的协程提供Stop方法,其实不然,可以通过MonoBehaviour enabled = false 或者 gameObject.active = false 就可以停止协程的执行『2』。
& & & & 经过验证,『2』的结论也是错误的,正确的结论是,MonoBehaviour.enabled = false 协程会照常运行,但 gameObject.SetActive(false) 后协程却全部停止,即使在Inspector把 &gameObject 激活还是没有继续执行:
using UnityE
using System.C
public class TestCoroutine : MonoBehaviour {
private bool isStartCall =
//Makesure Update() and LateUpdate() Log only once
private bool isUpdateCall =
private bool isLateUpdateCall =
// Use this for initialization
void Start () {
if (!isStartCall)
Debug.Log("Start Call Begin");
StartCoroutine(StartCoutine());
Debug.Log("Start Call End");
isStartCall =
IEnumerator StartCoutine()
Debug.Log("This is Start Coroutine Call Before");
yield return new WaitForSeconds(1f);
Debug.Log("This is Start Coroutine Call After");
// Update is called once per frame
void Update () {
if (!isUpdateCall)
Debug.Log("Update Call Begin");
StartCoroutine(UpdateCoutine());
Debug.Log("Update Call End");
isUpdateCall =
this.enabled =
//this.gameObject.SetActive(false);
IEnumerator UpdateCoutine()
Debug.Log("This is Update Coroutine Call Before");
yield return new WaitForSeconds(1f);
Debug.Log("This is Update Coroutine Call After");
yield return new WaitForSeconds(1f);
Debug.Log("This is Update Coroutine Call Second");
void LateUpdate()
if (!isLateUpdateCall)
Debug.Log("LateUpdate Call Begin");
StartCoroutine(LateCoutine());
Debug.Log("LateUpdate Call End");
isLateUpdateCall =
IEnumerator LateCoutine()
Debug.Log("This is Late Coroutine Call Before");
Debug.Log("This is Late Coroutine Call After");
&先在Update中调用 this.enabled = 得到的结果:
然后把 this.enabled = 注释掉,换成 this.gameObject.SetActive(false); 得到的结果如下:
& & & & 整理得到
:通过设置MonoBehaviour脚本的enabled对协程是没有影响的,但如果 gameObject.SetActive(false) 则已经启动的协程则完全停止了,即使在Inspector把gameObject 激活还是没有继续执行。也就说协程虽然是在MonoBehvaviour启动的(StartCoroutine)但是协程函数的地位完全是跟MonoBehaviour是一个层次的,不受MonoBehaviour的状态影响,但跟MonoBehaviour脚本一样受gameObject 控制,也应该是和MonoBehaviour脚本一样每帧“轮询” yield 的条件是否满足。
yield 后面可以有的表达式:
& & & &a) null - the coroutine executes the next time that it is eligible
& & & &b) WaitForEndOfFrame - the coroutine executes on the frame, after all of the rendering and GUI is complete
& & & &c) WaitForFixedUpdate - causes this coroutine to execute at the next physics step, after all physics is calculated
& & & &d) WaitForSeconds - causes the coroutine not to execute for a given game time period
& & & &e) WWW - waits for a web request to complete (resumes as if WaitForSeconds or null)
& & & &f) Another coroutine - in which case the new coroutine will run to completion before the yielder is resumed
值得注意的是 WaitForSeconds()受Time.timeScale影响,当Time.timeScale = 0f 时,yield return new WaitForSecond(x) 将不会满足。
IEnumerator & Coroutine
& & & & 协程其实就是一个IEnumerator(迭代器),IEnumerator 接口有两个方法 Current 和 MoveNext() ,前面介绍的TaskManager就是利用者两个方法对协程进行了管理,这里在介绍一个协程的交叉调用类 Hijack(参见附件):
using System.Collections.G
using System.L
using UnityE
using System.C
[RequireComponent(typeof(GUIText))]
public class Hijack : MonoBehaviour {
//This will hold the counting up coroutine
IEnumerator _countUp;
//This will hold the counting down coroutine
IEnumerator _countD
//This is the coroutine we are currently
//hijacking
IEnumerator _
//A value that will be updated by the coroutine
//that is currently running
int value = 0;
void Start()
//Create our count up coroutine
_countUp = CountUp();
//Create our count down coroutine
_countDown = CountDown();
//Start our own coroutine for the hijack
StartCoroutine(DoHijack());
void Update()
//Show the current value on the screen
guiText.text = value.ToString();
void OnGUI()
//Switch between the different functions
if(GUILayout.Button("Switch functions"))
if(_current == _countUp)
_current = _countD
_current = _countUp;
IEnumerator DoHijack()
while(true)
//Check if we have a current coroutine and MoveNext on it if we do
if(_current != null && _current.MoveNext())
//Return whatever the coroutine yielded, so we will yield the
//same thing
yield return _current.C
//Otherwise wait for the next frame
IEnumerator CountUp()
//We have a local increment so the routines
//get independently faster depending on how
//long they have been active
float increment = 0;
while(true)
//Exit if the Q button is pressed
if(Input.GetKey(KeyCode.Q))
increment+=Time.deltaT
value += Mathf.RoundToInt(increment);
IEnumerator CountDown()
float increment = 0f;
while(true)
if(Input.GetKey(KeyCode.Q))
increment+=Time.deltaT
value -= Mathf.RoundToInt(increment);
//This coroutine returns a yield instruction
yield return new WaitForSeconds(0.1f);
&上面的代码实现是两个协程交替调用,对有这种需求来说实在太精妙了。
& & & & 今天仔细看了下UnityGems.com 有关Coroutine的两篇文章,虽然第一篇(参考①)现在验证的结果有很多错误,但对于理解协程还是不错的,尤其是当我发现Hijack这个脚本时,就迫不及待分享给大家。
& & & & 本来没觉得会有UnityGems.com上的文章会有错误的,无意测试了发现还是有很大的出入,当然这也不是说原来作者没有经过验证就妄加揣测,D.S.Qiu觉得很有可能是Unity内部的实现机制改变了,这种东西完全可以改动,Unity虽然开发了很多年了,但是其实在实际开发中还是有很多坑,越发觉得Unity的无力,虽说容易上手,但是填坑的功夫也是必不可少的。& & &&
& & & & 看来很多结论还是要通过自己的验证才行,贸然复制粘贴很难出真知,切记!
& & & & 如果您对D.S.Qiu有任何建议或意见可以在文章后面评论,或者发邮件(gd.s.)交流,您的鼓励和支持是我前进的动力,希望能有更多更好的分享。
& & & & 转载请在文首注明出处:
更多精彩请关注D.S.Qiu的博客和微博(ID:静水逐风) & &
①UnityGems.com:&
②UnityGems.com:&
馆藏&21399
TA的最新馆藏[转]&[转]&[转]&[转]&[转]&[转]&[转]&
喜欢该文的人也喜欢没有更多推荐了,
不良信息举报
举报内容:
StopCoroutine协程停止
举报原因:
原文地址:
原因补充:
最多只允许输入30个字
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!From Unify Community Wiki
Author: Fernando Zapata ()
ported to CSharp by Frank Otto ()
Additional implementation for yield commands from the UnityEngine namespace by Gareth Williams ()
A simple coroutine scheduler. This coroutine scheduler allows for complete
control over the execution regime of a set of coroutines. Reading the code
will also help you understand how coroutines work behind the scenes.
Understanding how coroutines are built on top of .Net generators will allow
you to add coroutine support to a non-Unity project.
Coroutines can yield until the next update "", until a given number of
updates have passed "yield anI", until a given amount of seconds have passed
"yield aF", or until another coroutine has finished
"yield scheduler.StartCoroutine(Coroutine());".
Multiple scheduler instances are supported and can be very useful. A
coroutine running under one scheduler can yield (wait) for a coroutine
running under a completely different scheduler instance.
Unity's YieldInstruction classes are not used because I cannot
access their internal data needed for scheduling. Semantics are slightly
different from Unity's scheduler. For example, in Unity if you start a
coroutine it will run up to its first yield immediately, while in this
scheduler it will not run until the next time UpdateAllCoroutines is called.
This feature allows any code to start coroutines at any time, while
making sure the started coroutines only run at specific times.
You should not depend on update order between coroutines running on the same
For a deeper understanding and to learn more about how coroutines are implemented as state machines by the compiler see the article quoted in this .
Here's a link to a cached version of the
which is way easier to read.
Creating and driving CoroutineSchedulers is easy and is best shown by an example.
var scheduler = new CoroutineScheduler&#40;&#41;;
function Update&#40;&#41; &#123;
scheduler.UpdateAllCoroutines&#40;Time.frameCount, Time.time&#41;;
You normally would not use Unity's own Time.frameCount or Time.time as in that case you may as well use Unity's built-in scheduler, but it makes for an easy to understand example.
Starting coroutines and yielding execution is also best shown by an example.
scheduler.StartCoroutine&#40;MyCoroutine&#40;&#41;&#41;;
function MyCoroutine&#40;&#41; : IEnumerator &#123;
print&#40;&MyCoroutine: Begin&&#41;;
yield; // wait for next update
print&#40;&MyCoroutine:&&#41;;
yield 2; // wait for 2 updates,
print&#40;&MyCoroutine: After yield 2;&&#41;;
yield 3.5; // wait for 3.5 seconds
print&#40;&MyCoroutine: After 3.5&&#41;;
// you can also yield for a coroutine running on a completely different scheduler instance
yield scheduler.StartCoroutine&#40;WaitForMe&#40;&#41;&#41;;
print&#40;&MyCoroutine: After WaitForMe()&&#41;;
function WaitForMe&#40;&#41; &#123;
yield 7.8; // wait for 7.8 seconds before finishing
For details on features not used in this particular example please read the doc comments. If you have any questions feel free to contact me directly at .
#pragma strict
* A simple coroutine scheduler. Coroutines can yield until the next update
* &&, until a given number of updates &yield anInt&, until a given
* amount of seconds &yield aF&, or until another coroutine has finished
* &yield scheduler.StartCoroutine(Coroutine())&.
* Multiple scheduler instances are supported and can be very useful. A
* coroutine running under one scheduler can yield (wait) for a coroutine
* running under a completely different scheduler instance.
* Unity's YieldInstruction classes are not used because I cannot
* access their internal data needed for scheduling. Semantics are slightly
* different from Unity's scheduler. For example, in Unity if you start a
* coroutine it will run up to its first yield immediately, while in this
* scheduler it will not run until the next time UpdateAllCoroutines is called.
* This feature allows any code to start coroutines at any time, while
* making sure the started coroutines only run at specific times.
* You should not depend on update order between coroutines running on the same
* update. For example, StartCoroutine(A), StartCoroutine(B), StartCoroutine(C)
* where A, B, C =& while(true) { print(A|B|C); }, do not expect &ABC& or
* &CBA& or any other specific ordering.
class CoroutineScheduler &#123;
* The first node in list of the coroutines that are scheduled for execution.
var first : CoroutineNode = null;
var currentFrame : int;
var currentTime : float;
* Starts a coroutine, the coroutine does not run immediately but on the
* next call to UpdateAllCoroutines. The execution of a coroutine can
* be paused at any point using the yield statement. The yield return value
* specifies when the coroutine is resumed.
function StartCoroutine&#40;fiber : IEnumerator&#41; : CoroutineNode &#123;
// if function does not have a yield, fiber will be null and we no-op
if &#40;fiber == null&#41; &#123; return; &#125;
// create coroutine node and run until we reach first yield
var coroutine = new CoroutineNode&#40;fiber&#41;;
AddCoroutine&#40;coroutine&#41;;
return coroutine;
* Stops all coroutines running on this behaviour. Use of this method is
* discouraged, think of a natural way for your coroutines to finish
* on their own instead of being forcefully stopped before they finish.
* If you need finer control over stopping coroutines you can use multiple
* schedulers.
function StopAllCoroutines&#40;&#41; &#123;
first = null;
* Returns true if this scheduler has any coroutines. You can use this to
* check if all coroutines have finished or been stopped.
function HasCoroutines&#40;&#41; : boolean &#123;
return first != null;
* Runs all active coroutines until their next yield. Caller must provide
* the current frame and time. This allows for schedulers to run under
* frame and time regimes other than the Unity's main game loop.
function UpdateAllCoroutines&#40;frame : int, time : float&#41; &#123;
currentFrame = frame;
currentTime = time;
var coroutine = first;
while &#40;coroutine != null&#41; &#123;
// store listNext before coroutine finishes and is removed from the list
var listNext = coroutine.listNext;
if &#40;coroutine.waitForFrame & 0 && frame &= coroutine.waitForFrame&#41; &#123;
coroutine.waitForFrame = -1;
UpdateCoroutine&#40;coroutine&#41;;
&#125; else if &#40;coroutine.waitForTime & 0.0 && time &= coroutine.waitForTime&#41; &#123;
coroutine.waitForTime = -1.0;
UpdateCoroutine&#40;coroutine&#41;;
&#125; else if &#40;coroutine.waitForCoroutine &&
coroutine.waitForCoroutine.finished&#41; &#123;
coroutine.waitForCoroutine = null;
UpdateCoroutine&#40;coroutine&#41;;
&#125; else if &#40;coroutine.waitForFrame == -1 &&
coroutine.waitForTime == -1.0 &&
coroutine.waitForCoroutine == null&#41; &#123; // initial update
UpdateCoroutine&#40;coroutine&#41;;
coroutine = listNext;
* Executes coroutine until next yield. If coroutine has finished, flags
* it as finished and removes it from scheduler list.
private function UpdateCoroutine&#40;coroutine : CoroutineNode&#41; &#123;
var fiber = coroutine.fiber;
if &#40;coroutine.fiber.MoveNext&#40;&#41;&#41; &#123;
var yieldCommand : Object = &#40;fiber.Current == null&#41; ? 1 : fiber.Current;
if &#40;yieldCommand instanceof int&#41; &#123;
coroutine.waitForFrame = yieldCommand;
coroutine.waitForFrame += currentFrame;
&#125; else if &#40;yieldCommand instanceof float&#41; &#123;
coroutine.waitForTime = yieldCommand;
coroutine.waitForTime +=
currentTime;
&#125; else if
&#40;yieldCommand instanceof CoroutineNode&#41; &#123;
coroutine.waitForCoroutine = yieldCommand;
&#125; else &#123;
throw &Unexpected coroutine yield type: & + yieldCommand.GetType&#40;&#41;;
&#125; else &#123; // coroutine finished
coroutine.finished = true;
RemoveCoroutine&#40;coroutine&#41;;
private function AddCoroutine&#40;coroutine : CoroutineNode&#41; &#123;
if &#40;first != null&#41; &#123;
coroutine.listNext = first;
first.listPrevious = coroutine;
first = coroutine;
private function RemoveCoroutine&#40;coroutine : CoroutineNode&#41; &#123;
if &#40;first == coroutine&#41; &#123; // remove first
first = coroutine.listNext;
&#125; else &#123; // not head of list
if &#40;coroutine.listNext != null&#41; &#123; // remove between
coroutine.listPrevious.listNext = coroutine.listNext;
coroutine.listNext.listPrevious = coroutine.listPrevious;
&#125; else if &#40;coroutine.listPrevious != null&#41; &#123; // and listNext is null
coroutine.listPrevious.listNext = null; // remove last
coroutine.listPrevious = null;
coroutine.listNext = null;
#pragma strict
* Linked list node type used by coroutine scheduler to track scheduling of
* coroutines.
class CoroutineNode &#123;
var listPrevious : CoroutineNode = null;
var listNext : CoroutineNode = null;
var fiber : IEnumerator;
var finished = false;
var waitForFrame = -1;
var waitForTime = -1.0;
var waitForCoroutine : CoroutineNode = null;
function CoroutineNode&#40;fiber : IEnumerator&#41; &#123;
this.fiber = fiber;
Ported to CSharp
using UnityEngine;
using System.Collections;
/// &summary&
/// CoroutineSchedulerTest.cs
/// Port of the Javascript version from
/// http://www.unifycommunity.com/wiki/index.php?title=CoroutineScheduler
/// Linked list node type used by coroutine scheduler to track scheduling of coroutines.
/// BMBF Researchproject http://playfm.htw-berlin.de
/// PlayFM - Serious Games für den IT-gestützten Wissenstransfer im Facility Management
/// Gef?rdert durch das bmb+f - Programm Forschung an Fachhochschulen profUntFH
/// &author&Frank.Otto@htw-berlin.de&/author&
/// &/summary&
public class CoroutineSchedulerTest : MonoBehaviour
CoroutineScheduler scheduler;
// Use this for initialization
void Start &#40;&#41;
scheduler = new CoroutineScheduler &#40;&#41;;
scheduler.StartCoroutine &#40;MyCoroutine &#40;&#41;&#41;;
IEnumerator MyCoroutine &#40;&#41;
Debug.Log &#40;&MyCoroutine: Begin&&#41;;
yield return 0;
// wait for next update
Debug.Log &#40;&MyCoroutine:& + Time.time&#41;;
yield return 2;
// wait for 2 updates,
Debug.Log &#40;&MyCoroutine: After yield 2;& + Time.time&#41;;
yield return 3.5f;
// wait for 3.5 seconds
Debug.Log &#40;&MyCoroutine: After 3.5& + Time.time&#41;;
// you can also yield for a coroutine running on a completely different scheduler instance
yield return scheduler.StartCoroutine &#40;WaitForMe &#40;&#41;&#41;;
Debug.Log &#40;&MyCoroutine: After WaitForMe()& + Time.time&#41;;
IEnumerator WaitForMe &#40;&#41;
yield return 7.8f;
// wait for 7.8 seconds before finishing
// Update is called once per
void Update &#40;&#41;
scheduler.UpdateAllCoroutines &#40;Time.frameCount, Time.time&#41;;
using System.Collections;
using UnityEngine;
/// &summary&
/// CoroutineScheduler.cs
/// Port of the Javascript version from
/// http://www.unifycommunity.com/wiki/index.php?title=CoroutineScheduler
/// Linked list node type used by coroutine scheduler to track scheduling of coroutines.
/// BMBF Researchproject http://playfm.htw-berlin.de
/// PlayFM - Serious Games für den IT-gestützten Wissenstransfer im Facility Management
/// Gef?rdert durch das bmb+f - Programm Forschung an Fachhochschulen profUntFH
/// &author&Frank.Otto@htw-berlin.de&/author&
/// A simple coroutine scheduler. Coroutines can yield until the next update
/// &&, until a given number of updates &yield anInt&, until a given
/// amount of seconds &yield aF&, or until another coroutine has finished
/// &yield scheduler.StartCoroutine(Coroutine())&.
/// Multiple scheduler instances are supported and can be very useful. A
/// coroutine running under one scheduler can yield (wait) for a coroutine
/// running under a completely different scheduler instance.
/// Unity's YieldInstruction classes are not used because I cannot
/// access their internal data needed for scheduling. Semantics are slightly
/// different from Unity's scheduler. For example, in Unity if you start a
/// coroutine it will run up to its first yield immediately, while in this
/// scheduler it will not run until the next time UpdateAllCoroutines is called.
/// This feature allows any code to start coroutines at any time, while
/// making sure the started coroutines only run at specific times.
/// You should not depend on update order between coroutines running on the same
/// update. For example, StartCoroutine(A), StartCoroutine(B), StartCoroutine(C)
/// where A, B, C =& while(true) { print(A|B|C); }, do not expect &ABC& or
/// &CBA& or any other specific ordering.
/// &/summary&
public class CoroutineScheduler : MonoBehaviour
CoroutineNode first = null;
int currentFrame;
float currentTime;
* Starts a coroutine, the coroutine does not run immediately but on the
* next call to UpdateAllCoroutines. The execution of a coroutine can
* be paused at any point using the yield statement. The yield return value
* specifies when the coroutine is resumed.
public CoroutineNode StartCoroutine &#40;IEnumerator fiber&#41;
// if function does not have a yield, fiber will be null and we no-op
if &#40;fiber == null&#41; &#123;
return null;
// create coroutine node and run until we reach first yield
CoroutineNode coroutine = new CoroutineNode &#40;fiber&#41;;
AddCoroutine &#40;coroutine&#41;;
return coroutine;
* Stops all coroutines running on this behaviour. Use of this method is
* discouraged, think of a natural way for your coroutines to finish
* on their own instead of being forcefully stopped before they finish.
* If you need finer control over stopping coroutines you can use multiple
* schedulers.
public void StopAllCoroutines &#40;&#41;
first = null;
* Returns true if this scheduler has any coroutines. You can use this to
* check if all coroutines have finished or been stopped.
public bool HasCoroutines &#40;&#41;
return first != null;
* Runs all active coroutines until their next yield. Caller must provide
* the current frame and time. This allows for schedulers to run under
* frame and time regimes other than the Unity's main game loop.
public void UpdateAllCoroutines &#40;int frame, float time&#41;
currentFrame = frame;
currentTime = time;
CoroutineNode coroutine = this.first;
while &#40;coroutine != null&#41; &#123;
// store listNext before coroutine finishes and is removed from the list
CoroutineNode listNext = coroutine.listNext;
if &#40;coroutine.waitForFrame & 0 && frame &= coroutine.waitForFrame&#41; &#123;
coroutine.waitForFrame = -1;
UpdateCoroutine &#40;coroutine&#41;;
&#125; else if &#40;coroutine.waitForTime & 0.0f && time &= coroutine.waitForTime&#41; &#123;
coroutine.waitForTime = -1.0f;
UpdateCoroutine &#40;coroutine&#41;;
&#125; else if &#40;coroutine.waitForCoroutine != null && coroutine.waitForCoroutine.finished&#41; &#123;
coroutine.waitForCoroutine = null;
UpdateCoroutine &#40;coroutine&#41;;
&#125; else if &#40;coroutine.waitForFrame == -1 && coroutine.waitForTime == -1.0f && coroutine.waitForCoroutine == null&#41; &#123;
// initial update
UpdateCoroutine &#40;coroutine&#41;;
coroutine = listNext;
* Executes coroutine until next yield. If coroutine has finished, flags
* it as finished and removes it from scheduler list.
private void UpdateCoroutine &#40;CoroutineNode coroutine&#41;
IEnumerator fiber = coroutine.fiber;
if &#40;coroutine.fiber.MoveNext &#40;&#41;&#41; &#123;
System.Object yieldCommand = fiber.Current == null ? &#40;System.Object&#41; 1 : fiber.Current;
if &#40;yieldCommand.GetType &#40;&#41; == typeof&#40;int&#41;&#41; &#123;
coroutine.waitForFrame = &#40;int&#41; yieldCommand;
coroutine.waitForFrame += &#40;int&#41; currentFrame;
&#125; else if &#40;yieldCommand.GetType &#40;&#41; == typeof&#40;float&#41;&#41; &#123;
coroutine.waitForTime = &#40;float&#41; yieldCommand;
coroutine.waitForTime += &#40;float&#41; currentTime;
&#125; else if &#40;yieldCommand.GetType &#40;&#41; == typeof&#40;CoroutineNode&#41;&#41; &#123;
coroutine.waitForCoroutine = &#40;CoroutineNode&#41; yieldCommand;
&#125; else &#123;
throw new System.ArgumentException &#40;&CoroutineScheduler: Unexpected coroutine yield type: & + yieldCommand.GetType &#40;&#41;&#41;;
&#125; else &#123;
// coroutine finished
coroutine.finished = true;
RemoveCoroutine &#40;coroutine&#41;;
private void AddCoroutine &#40;CoroutineNode coroutine&#41;
if &#40;this.first != null&#41; &#123;
coroutine.listNext = this.first;
first.listPrevious = coroutine;
first = coroutine;
private void RemoveCoroutine &#40;CoroutineNode coroutine&#41;
if &#40;this.first == coroutine&#41; &#123;
// remove first
this.first = coroutine.listNext;
&#125; else &#123;
// not head of list
if &#40;coroutine.listNext != null&#41; &#123;
// remove between
coroutine.listPrevious.listNext = coroutine.listNext;
coroutine.listNext.listPrevious = coroutine.listPrevious;
&#125; else if &#40;coroutine.listPrevious != null&#41; &#123;
// and listNext is null
coroutine.listPrevious.listNext = null;
// remove last
coroutine.listPrevious = null;
coroutine.listNext = null;
&#125;//class
using System.Collections;
using UnityEngine;
/// &summary&
/// CoroutineNode.cs
/// Port of the Javascript version from
/// http://www.unifycommunity.com/wiki/index.php?title=CoroutineScheduler
/// Linked list node type used by coroutine scheduler to track scheduling of coroutines.
/// BMBF Researchproject http://playfm.htw-berlin.de
/// PlayFM - Serious Games für den IT-gestützten Wissenstransfer im Facility Management
/// Gef?rdert durch das bmb+f - Programm Forschung an Fachhochschulen profUntFH
/// &author&Frank.Otto@htw-berlin.de&/author&
/// &/summary&
public class CoroutineNode
public CoroutineNode listPrevious = null;
public CoroutineNode listNext = null;
public IEnumerator fiber;
public bool finished = false;
public int waitForFrame = -1;
public float waitForTime = -1.0f;
public CoroutineNode waitForCoroutine;
public CoroutineNode &#40;IEnumerator _fiber&#41;
this.fiber = _fiber;
If you want to use CoroutineScheduler with Yield Commands from within the UnityEngine namespace here is an addition to the implementation, I found it useful for consuming api's in classes defined outside the UnityEngine namespace.
m_scheduler = new CoroutineScheduler&#40;&#41;;
m_scheduler.StartCoroutine&#40;testAPI&#40;&#41;&#41;;
IEnumerator testAPI&#40;&#41;
// ...set up request
var www = new UnityEngine.WWW&#40;requestURL&#41;;
yield return new UnityWWWYieldWrapper&#40;www&#41;;
// ...loading complete do some stuff
//line 110
public void UpdateAllCoroutines&#40;int frame, float time&#41;
currentFrame = frame;
currentTime = time;
CoroutineNode coroutine = this.first;
while &#40;coroutine != null&#41;
// store listNext before coroutine finishes and is removed from the list
CoroutineNode listNext = coroutine.listNext;
if &#40;coroutine.waitForFrame & 0 && frame &= coroutine.waitForFrame&#41;
coroutine.waitForFrame = -1;
UpdateCoroutine&#40;coroutine&#41;;
else if &#40;coroutine.waitForTime & 0.0f && time &= coroutine.waitForTime&#41;
coroutine.waitForTime = -1.0f;
UpdateCoroutine&#40;coroutine&#41;;
else if &#40;coroutine.waitForCoroutine != null && coroutine.waitForCoroutine.finished&#41;
coroutine.waitForCoroutine = null;
UpdateCoroutine&#40;coroutine&#41;;
else if &#40;coroutine.waitForUnityObject != null && coroutine.waitForUnityObject.finished&#41;//lonewolfwilliams
coroutine.waitForUnityObject = null;
UpdateCoroutine&#40;coroutine&#41;;
else if &#40;coroutine.waitForFrame == -1 && coroutine.waitForTime == -1.0f
&& coroutine.waitForCoroutine == null && coroutine.waitForUnityObject == null&#41;
// initial update
UpdateCoroutine&#40;coroutine&#41;;
coroutine = listNext;
//line 154
private void UpdateCoroutine&#40;CoroutineNode coroutine&#41;
IEnumerator fiber = coroutine.fiber;
if &#40;coroutine.fiber.MoveNext&#40;&#41;&#41;
System.Object yieldCommand = fiber.Current == null ? &#40;System.Object&#41;1 : fiber.Current;
if &#40;yieldCommand.GetType&#40;&#41; == typeof&#40;int&#41;&#41;
coroutine.waitForFrame = &#40;int&#41;yieldCommand;
coroutine.waitForFrame += &#40;int&#41;currentFrame;
else if &#40;yieldCommand.GetType&#40;&#41; == typeof&#40;float&#41;&#41;
coroutine.waitForTime = &#40;float&#41;yieldCommand;
coroutine.waitForTime += &#40;float&#41;currentTime;
else if &#40;yieldCommand.GetType&#40;&#41; == typeof&#40;CoroutineNode&#41;&#41;
coroutine.waitForCoroutine = &#40;CoroutineNode&#41;yieldCommand;
else if &#40;yieldCommand is IYieldWrapper&#41; //lonewolfwilliams
coroutine.waitForUnityObject = yieldCommand as IYieldWrapper;
throw new System.ArgumentException&#40;&CoroutineScheduler: Unexpected coroutine yield type: & + yieldCommand.GetType&#40;&#41;&#41;;
//this is an alternative if you don't have access to the function passed to the couroutineScheduler - maybe it's
//precompiled in a dll for example - remember you will have to add a case every time you add a wrapper&#160;:/
var commandType = yieldCommand.GetType();
if(commandType == typeof(UnityEngine.WWW))
coroutine.waitForUnityObject =
new UnityWWWWrapper(yieldCommand as UnityEngine.WWW);
else if(commandType == typeof(UnityEngine.AsyncOperation))
coroutine.waitForUnityObject =
new UnityASyncOpWrapper(yieldCommand as UnityEngine.AsyncOperation);
else if(commandType == typeof(UnityEngine.AssetBundleRequest))
coroutine.waitForUnityObject =
new UnityAssetBundleRequestWrapper(yieldCommand as UnityEngine.AssetBundleRequest);
throw new System.ArgumentException(&CoroutineScheduler: Unexpected coroutine yield type: & + yieldCommand.GetType());
// coroutine finished
coroutine.finished = true;
RemoveCoroutine&#40;coroutine&#41;;
public class CoroutineNode
public CoroutineNode listPrevious = null;
public CoroutineNode listNext = null;
public IEnumerator fiber;
public bool finished = false;
public int waitForFrame = -1;
public float waitForTime = -1.0f;
public CoroutineNode waitForCoroutine;
public IYieldWrapper waitForUnityObject; //lonewolfwilliams
public CoroutineNode&#40;IEnumerator _fiber&#41;
this.fiber = _fiber;
you will need to write your own implementations for yield commands from within the UnityEngine namespace, this interface should help facilitate that.
* gareth williams
* http://www.lonewolfwilliams.com
public interface IYieldWrapper
bool finished &#123; get; &#125;
Below are some examples of wrappers I have used, in fact they have almost identical signatures so a more generic implementation could probably be written ^_^
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
Gareth Williams
http://www.lonewolfwilliams.com
class UnityASyncOpWrapper : IYieldWrapper
private UnityEngine.AsyncOperation m_UnityObject;
public bool finished
return m_UnityObject.isDone;
public UnityASyncOpWrapper&#40;UnityEngine.AsyncOperation wraps&#41;
m_UnityObject = wraps;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
* Gareth Williams
* http://www.lonewolfwilliams.com
public class UnityWWWYieldWrapper : IYieldWrapper
private UnityEngine.WWW m_UnityObject;
public bool finished
return m_UnityObject.isDone;
public UnityWWWYieldWrapper&#40;UnityEngine.WWW wraps&#41;
m_UnityObject = wraps;
Quick Links}

我要回帖

更多关于 空调制热老是自动停止 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信