关于UnityStartCoroutine(协程)的使用总结

本文通过一个简单例子阐述了Unity3D中协程的概念、使用方法及与线程的区别,展示了协程如何避免大量运算导致的界面卡死问题,以及如何在C#中使用IEnumerator和yield关键字来实现协程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

StartCoroutine在unity3d的帮助中叫做协程,意思就是启动一个辅助的线程。

在C#中直接有Thread这个线程,但是在unity中有些元素是不能操作的。这个时候可以使用协程来完成。

使用线程的好处就是不会出现界面卡死的情况,如果有一次非常大量的运算,没用线程就会出现假死的情况。

下面通过一个简单的例子来说明使用协程的好处:

 

 

  1. void OnGUI()  
  2.     {  
  3.         GUI.Label(new Rect(0, 0, 200, 50), "测试1:" + result);  
  4.         if (GUI.Button(new Rect(0, 100, 100, 50), "开启协程"))  
  5.         {  
  6.             StartCoroutine(GetResult());  
  7.         }  
  8.   
  9.         GUI.Label(new Rect(200, 0, 200, 50), "测试2:" + result1);  
  10.         if (GUI.Button(new Rect(200, 100, 100, 50), "无协程测试"))  
  11.         {  
  12.             GetResult1();  
  13.         }  
  14.     }  

上面的代码表示在GUI中定义2个label和按钮,一个按钮启动协程计算,另一个直接计算结果。由于2个方法都是计算同样的结果,计算量比较大,所以直接计算出现了暂时的卡死情况。

 

  1. float result;  
  2.     IEnumerator GetResult()  
  3.     {  
  4.         for (int i = 0; i < 1000; i++)  
  5.         {  
  6.             for (int j = 0; j < 100000; j++)  
  7.             {  
  8.                 result += (i + j);  
  9.                   
  10.             }  
  11.             if(i%100==0)  
  12.                 yield return 1;  
  13.               
  14.         }  
  15.     }  

这个方法是协程的写法,在C#中协程要定义为IEnumerator 这个类型,javascript中不需要。

yield return 1;这句话表示返回1帧的结果。在i为100的整数时,就返回一次结果,这样可以避免大量的计算卡死。

 

 

  1. float result1;  
  2.     void GetResult1()  
  3.     {  
  4.         for (int i = 0; i < 1000; i++)  
  5.         {  
  6.             for (int j = 0; j < 100000; j++)  
  7.             {  
  8.                 result1 += (i + j);  
  9.             }  
  10.         }  
  11.     }  

 

 

这个方法就是直接计算结果,由于运算量比较大,所以界面会卡死,这样就可以体现出用协程的好处了。
使用IEnumerator 这个类型时,必须用yield return来返回结果,参数为数字时表示为帧数。
如yield return 1 表示每一帧返回一次结果。



-------------------------------------------


http://blog.163.com/hj_0467/blog/static/74252563201011711845180/

http://wg2009perfect.blog.163.com/blog/static/127997663201211111222126/

 

我在这摘要下:

1.

coroutine,中文翻译“协程”。这个概念可能有点冷门,不过百度之,说是一种很古老的编程模型了,以前的操作系统里进程调度里用到过,现在操作系统的进程调度都是根据时间片和优先级来进行轮换,以前是要程序自己来释放cpu的控制权,一直不释放一直也就占用着cpu,这种要求程序自己来进行调度的编程模型应该就叫“协程”了。

协程和线程差不多,线程的调度是由操作系统完成的,协程把这项任务交给了程序员自己实现,当然也就可以提高灵活性,另外协程的开销比线程要小,在程序里可以开更多的协程。

一些语言里自带了对coroutine的实现,比如lua。c里面虽然没有coroutine,不过windows下提供了一种叫fiber的机制,叫做“纤程”,算是一种轻量级线程。

 

2.

 

一。什么是协同程序

       协同程序,即在主程序运行时同时开启另一段逻辑处理,来协同当前程序的执行。换句话说,开启协同程序就是开启一个线程。

 

二。协同程序的开启与终止

       在Unity3D中,使用MonoBehaviour.StartCoroutine方法即可开启一个协同程序,也就是说该方法必须在MonoBehaviour或继承于MonoBehaviour的类中调用。

       在Unity3D中,使用StartCoroutine(string methodName)和StartCoroutine(IEnumerator routine)都可以开启一个线程。区别在于使用字符串作为参数可以开启线程并在线程结束前终止线程,相反使用IEnumerator 作为参数只能等待线程的结束而不能随时终止(除非使用StopAllCoroutines()方法);另外使用字符串作为参数时,开启线程时最多只能传递一个参数,并且性能消耗会更大一点,而使用IEnumerator 作为参数则没有这个限制。

        在Unity3D中,使用StopCoroutine(string methodName)来终止一个协同程序,使用StopAllCoroutines()来终止所有可以终止的协同程序,但这两个方法都只能终止该MonoBehaviour中的协同程序。

        还有一种方法可以终止协同程序,即将协同程序所在gameobject的active属性设置为false,当再次设置active为ture时,协同程序并不会再开启;如是将协同程序所在脚本的enabled设置为false则不会生效。这是因为协同程序被开启后作为一个线程在运行,而MonoBehaviour也是一个线程,他们成为互不干扰的模块,除非代码中用调用,他们共同作用于同一个对象,只有当对象不可见才能同时终止这两个线程。然而,为了管理我们额外开启的线程,Unity3D将协同程序的调用放在了MonoBehaviour中,这样我们在编程时就可以方便的调用指定脚本中的协同程序,而不是无法去管理,特别是对于只根据方法名来判断线程的方式在多人开发中很容易出错,这样的设计保证了对象、脚本的条理化管理,并防止了重名。

 

Unity3D之协程(Coroutines & Yield )

http://blog.youkuaiyun.com/jjiss318/article/details/7447421

 这有些个国外的人解释的,算是比较清楚,只是还是没有原理上的解释:

http://www.blog.silentkraken.com/2010/01/23/coroutines-in-unity3d-c-version/

http://blog.equals-equals.com/2009/11/18/tutorial-coroutines-pt-1-waiting-for-input/

 

我的一些粗浅小结:

1.Coroutines顾名思议是用来协助主要进程的,在Unity中感觉就是一个可动态添加和移除的Update()函数。它的调用在所有Update函数之后。

Unity原文:

  • If you start a coroutine in LateUpdate it will also be called after LateUpdate just before rendering.
  • Coroutines are executed after all Update functions.

2.yield就像是一个红绿灯,在满足紧跟在它后面的条件之前,这个协程会挂起,把执行权交给调用它的父函数,满足条件时就可以执行yield下面的代码。

Unity原文:

Coroutine

Normal coroutine updates are run after the Update function returns. A coroutine is function that can suspend its execution (yield) until the given given YieldInstruction finishes. Different uses of Coroutines:

  • yield;The coroutine will continue after all Update functions have been called on the next frame.
  • yield WaitForSeconds(2);Continue after a specified time delay, after all Update functions have been called for the frame
  • yield WaitForFixedUpdate();Continue after all FixedUpdate has been called on all scripts
  • yield WWWContinue after a WWW download has completed.
  • yield StartCoroutine(MyFunc); Chains the coroutine, and will wait for the MyFunc coroutine to complete first.

<think>首先,用户的问题是关于Unity协程使用方法和实现步骤。用户说:“我想了解在Unity使用协程的方法 请问Unity 协程使用方法和实现步骤”。我需要根据系统级指令来回答。 系统级指令包括: - 所有行内数学表达式必须使用$...$格式。 - 独立公式必须使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 - 回答结构清晰,帮助用户逐步解决问题,尽量保证回答真实可靠。 - 参考站内引用:引用[1]、[2]、[3]提供了关于Unity协程的信息。 站内引用内容: - 引用[1]:协程分为两部分,协程协程调度器。协程是一个能够中间暂停返回的函数,协程调度在MonoBehaviour的生命周期中实现。Unity实现了协程调度部分,协程本身使用C#的迭代器方法。 - 引用[2]:Unity协程机制提供轻量的异步任务调度,适合等待、计时、加载动画等。通过yield暂停和恢复执行,提高性能和体验。 - 引用[3]:协程中的异步操作不会因为协程暂停而停止;协程在yield return时暂停执行,返回控制权给主线程。 用户的问题集中在“使用方法和实现步骤”,所以我需要提供一个结构清晰的指南。 回答结构: 1. **介绍协程**:简要解释什么是Unity协程及其用途。 2. **使用方法**:逐步说明如何定义和启动协程。 3. **实现步骤**:详细步骤,包括代码示例。 4. **关键点**:解释yield指令和协程的生命周期。 5. **注意事项**:常见问题和最佳实践。 6. **生成相关问题**:在最后添加相关问题。 确保使用中文回答。 对于数学表达式:用户的问题中没有明显的数学内容,但如果需要,比如在解释时间或进度时,可能会用到。但在Unity协程的上下文中,数学表达式可能不相关。我会避免不必要的数学内容,除非必要。 引用标识:在回答中,当引用站内内容时,在段落末尾添加[^n]。例如,如果基于引用[1]解释协程结构,就添加[^1]。 步骤: - 开头介绍协程。 - 使用方法:如何定义协程使用IEnumerator),如何启动(StartCoroutine)。 - 实现步骤:示例代码。 - 解释yield指令。 - 注意事项。 - 最后生成相关问题。 代码示例:用户提供了快速排序的示例,所以我应该包括一个协程的代码块。在Markdown中,使用```python或```csharp,但Unity使用C#,所以用```csharp。 相关问题:在最后添加“相关问题”部分。 完整回答结构: 1. 引言:什么是Unity协程。 2. 使用方法:定义和启动协程。 3. 实现步骤:详细步骤。 4. 关键特性:yield指令、暂停和恢复。 5. 注意事项。 6. 代码示例。 7. 相关问题。 现在,基于引用整合信息: - 引用[1]:协程是C#的迭代器方法,Unity处理调度。 - 引用[2]:协程用于异步任务,轻量高效。 - 引用[3]:yield return暂停协程但不停止异步操作。 在回答中自然地引用。</think>### Unity协程使用方法和实现步骤 Unity协程是一种轻量的异步编程机制,允许函数在执行过程中暂停和恢复,特别适用于游戏开发中的延时、动画、加载等任务。它基于C#的迭代器方法实现,并由Unity引擎在MonoBehaviour生命周期中调度。协程的核心是使用`yield`指令暂停执行,并在适当时机恢复,避免阻塞主线程[^1][^2]。下面我将逐步解释使用方法和实现步骤,确保结构清晰。 #### 1. **协程的基本概念** - 协程是一个返回`IEnumerator`接口的函数,通过`yield return`语句实现暂停点。 - Unity协程调度器在后台管理协程的恢复时机(如帧更新、计时器触发),无需开发者手动处理线程[^1][^2]。 - 优势:轻量高效,适合实现等待、计时、资源加载等异步操作,比多线程更易控制[^2]。 #### 2. **使用方法:定义和启动协程** 使用协程只需两个步骤:**定义协程函数**和**启动协程**。 - **步骤1: 定义协程函数** - 使用`IEnumerator`作为返回类型。 - 在函数体内插入`yield return`语句指定暂停条件(如等待时间、帧结束)。 - 示例:定义一个简单的延时协程。 ```csharp IEnumerator MyCoroutine() { Debug.Log("协程开始"); yield return new WaitForSeconds(2); // 暂停2秒 Debug.Log("2秒后恢复执行"); } ``` - `yield return`后可以是多种指令: - `WaitForSeconds(秒数)`:等待指定时间。 - `WaitForEndOfFrame`:等待当前帧结束。 - `null`:等待下一帧更新。 - 其他协程:实现协程嵌套。 - **步骤2: 启动协程** - 在MonoBehaviour脚本中调用`StartCoroutine()`方法启动。 - 示例:在`Start()`或`Update()`中启动上述协程。 ```csharp using UnityEngine; using System.Collections; public class CoroutineExample : MonoBehaviour { void Start() { StartCoroutine(MyCoroutine()); // 启动协程 } } ``` - 启动后,协程自动在后台运行,暂停时不会阻塞主线程[^3]。 #### 3. **实现步骤:详细指南** 以下是完整的实现流程,确保代码可运行: - **步骤1: 创建Unity脚本** - 在Unity编辑器中,新建C#脚本(如`CoroutineController.cs`)。 - **步骤2: 编写协程函数** - 定义`IEnumerator`函数,添加业务逻辑和暂停点。 - 示例:实现一个倒计时协程。 ```csharp IEnumerator CountdownCoroutine(int seconds) { for (int i = seconds; i > 0; i--) { Debug.Log($"倒计时: {i}"); yield return new WaitForSeconds(1); // 每秒暂停一次 } Debug.Log("倒计时结束"); } ``` - **步骤3: 启动和停止协程** - 启动:使用`StartCoroutine("函数名")`或`StartCoroutine(函数引用)`。 - 停止:使用`StopCoroutine("函数名")`或`StopAllCoroutines()`。 - 示例:在MonoBehaviour中管理协程。 ```csharp public class CoroutineController : MonoBehaviour { void Start() { StartCoroutine(CountdownCoroutine(5)); // 启动5秒倒计时 } void OnDisable() { StopAllCoroutines(); // 对象禁用时停止所有协程 } } ``` - **步骤4: 测试和调试** - 将脚本附加到GameObject上,运行Unity场景。 - 在Console窗口查看日志输出,验证协程暂停和恢复行为。 #### 4. **关键特性和注意事项** - **yield指令的作用**:`yield return`暂停协程执行,但不会停止异步操作(如网络请求);控制权返回主线程,协程在条件满足时自动恢复[^3]。 - **生命周期管理**:协程依赖于MonoBehaviour。如果脚本被禁用或对象销毁,协程会自动终止。建议在`OnDisable()`中显式停止协程[^1]。 - **性能优化**: - 避免在协程中执行耗时计算,以防帧率下降。 - 使用`Coroutine`对象跟踪协程状态(如`Coroutine myCoroutine = StartCoroutine(...)`)。 - 协程内存开销小,适合高频任务,但过度使用可能导致调度负担[^2]。 - **常见错误**: - 错误:直接在非MonoBehaviour类中启动协程——必须通过MonoBehaviour实例调用。 - 错误:忘记`yield return`——协程会立即执行完毕,失去暂停功能。 - 解决方案:使用Unity的调试工具检查协程状态。 #### 5. **应用示例** 以下是一个完整示例:实现物体渐隐效果。 ```csharp using UnityEngine; using System.Collections; public class FadeObject : MonoBehaviour { public Renderer rend; // 物体的渲染器组件 void Start() { rend = GetComponent<Renderer>(); StartCoroutine(FadeCoroutine()); } IEnumerator FadeCoroutine() { Color startColor = rend.material.color; for (float alpha = 1; alpha >= 0; alpha -= 0.1f) { startColor.a = alpha; rend.material.color = startColor; yield return new WaitForSeconds(0.1f); // 每0.1秒减少透明度 } Destroy(gameObject); // 渐变结束后销毁物体 } } ``` #### 总结 Unity协程通过简单的`IEnumerator`和`yield`机制,实现高效的异步控制。定义时注意暂停点,启动时使用`StartCoroutine`,并管理好生命周期以避免资源泄漏。协程是优化游戏逻辑(如动画序列、延时触发)的理想工具[^1][^2]。如需深入,可参考Unity官方文档或调试实践。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值