本帖最后由 da11 于 2023-3-11 22:09 编辑
协程的基础讲解及小练习1
Coroutines_Script.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Coroutines_Script : MonoBehaviour
{
/* 协程讲解
*
* - 与方法一样,协程也是一种程序组件。
* - 相对一般方法而言,协程更为灵活,方法只有一个入口,而协程可以有多个入口和出口点,可以用协程来实现任何的方法。
* - 协程更适合于用来实现如合作式多任务,迭代器,无限列表。
* - 开始一个协程时,执行从被调用方法的起始处开始;然而,接下来的每次协程被调用时,从协程返回(yield return)的位置接着执行。
* - 协程是单线程的!
*
* Unity中协程实现
* - IEnumerator接口 提供迭代
* - yield return xxxx 指定下一次迭代入口
* · WaitForFixedUpdate 在FixedUpdate后执行
* - 适合于物理控制
* · null、0、WaitForSeconds 在每帧Update后执行
* - 适合于分多帧完成一个任务,如A*路径计算
* · WaitForEndOfFrame 在每帧结束后执行
* - 适合于每帧末尾执行的操作,如相机的控制
* · WWW 在请求结束后执行
* - 适合于网络下载数据。(比如等待下载某个文件/图片,下载完成后执行)
*
* - StartCoroutine 开启协程-调用自定义协程的方法必须使用StartCoroutine开启协程,再调用具体的方法,否则协程无效!
* StartCoroutine 重载有三个调用方法
* 一、StartCoroutine(方法名(实参));
* 二、StartCoroutine("方法名");
* 三、StartCoroutine("方法名",obj对象);
*
* -注意,Update方法和OnGUI方法里面不能直接使用yield return协程入口,只能在Update调用其他协程方法来使用协程,否则会报错!
*
* 协程的停止
* · StopCoroutine(string)
* - StopCoroutine("协程方法名")
* - 只能停止以StartCoroutine("协程方法名")开启的协程!!
* · StopAllCoroutine("协程方法名")
* - 停止本对象中开启的"协程方法名"协程。
* · StopAllCoroutines()
* - 停止本对象中开启的所有协程。
*
* 使用协程的注意点:
* · 在程序中调用StopCoroutine()方法只能终止以字符串形式启动(开始)的协程
* · 多个协程可以同时运行,它们会根据各自的启动顺序来更新
* · 协程可以嵌套任意多层
* · 如果你想让多个脚本访问一个协程,那么你可以定义静态的协程
* · 协程不是多线程,它们运行在同一线程中,跟普通的脚本一样
* · 如果你的程序需要进行大量的计算,那么可以考虑在一个随时间进行的协程中处理它们
* · IEnumerator类型的方法不能带ref或者out型的参数
* · 目前在Unity中没有简便的方法来检测作用于对象的协程数量以及具体是哪些协程作用在对象上。
*
*
*/
public GameObject word1Obj; //协程练习1物体
private Color word1ObjColor; //协程练习1物体本身颜色
//不使用协程的start方法
private void Start1()
{
print("第一次输出");
print("第二次输出");
print("第三次输出");
}
//使用协程使用start方法,返回类型必须使用IEnumerator
//注意:IEnumerator返回方法类,如果没有使用yield return,方法会报错!
//IEnumerator和yield必须同时存在
private void Start()
{
//yield return 1; //迭代协程,下一次方法将在这里执行
//print("第一次输出");
//yield return new WaitForSeconds(1); //迭代协程,下一次方法将在这里执行,并且等待时间为1s,在start方法中模拟update的方法
//print("第二次输出");
//yield return new WaitForSeconds(2); //迭代协程,下一次方法将在这里执行,并且等待时间为2s,在start方法中模拟update的方法
//print("第三次输出");
//调用自定义协程的方法必须使用StartCoroutine开启协程,再调用具体的方法,否则协程无效!
//调用倒计时方法,模拟在update中执行,也比在update中执行方便许多
//StartCoroutine(TimeJS1(1));
word1ObjColor = word1Obj.GetComponent<MeshRenderer>().material.color;
}
//注意:使用StartCoroutine调用协程的这个方法,不能使用IEnumerator类型,如private void Update()不能使用成private IEnumerator Update()
private void Update()
{
//旧版Unity中,Update是不允许这样直接使用协程的,需要另外调用方法实现,新版Unity如果Update方法变更协程接口IEnumerator,则会显示没有引用
//yield return new WaitForSeconds(1);
//print("时间到");
//StartCoroutine(UpdateTimeFF());
}
private IEnumerator UpdateTimeFF()
{
yield return new WaitForSeconds(1);//为啥Update只执行了一次?
print("Update方法消息:1s时间到");
yield return new WaitForSeconds(2);//为啥Update只执行了一次?还有print("Update方法消息:1s时间到");已经执行很多条了,但是这条还没执行?
print("Update方法消息:2s时间到");
}
private void OnGUI1()
{
if (GUILayout.Button("开始计时"))
{
//调用自定义协程的方法必须使用StartCoroutine开启协程,再调用具体的方法,否则协程无效!
StartCoroutine(TimeJS(10));
}
}
//调用自定义协程的方法必须使用StartCoroutine开启协程,再调用具体的方法,否则协程无效!
private IEnumerator TimeJS(float TimeNum)
{
yield return new WaitForSeconds(TimeNum);
print(TimeNum + "秒时间到");
}
//使用协程自制一个简单的倒计时方法
private IEnumerator TimeJS1(float TimeNum)
{
while (TimeNum > 0)
{
TimeNum = TimeNum - 1;
yield return new WaitForSeconds(1);
print("倒计时还剩下: " + TimeNum + " 秒");
}
if (TimeNum == 0)
{
print("时间到");
}
}
//协程练习1:有一个物体,原本是白色的,点击攻击按钮物体变为红色(代表受到攻击),一秒后变回原来的颜色
private void OnGUI()
{
if (GUILayout.Button("攻击物体"))
{
StartCoroutine(ObjAttackStatic(word1Obj));
}
}
private IEnumerator ObjAttackStatic(GameObject Obj)
{
//点击攻击按钮物体变为红色(代表受到攻击)
Obj.GetComponent<MeshRenderer>().material.color = Color.red;
print("受到攻击了,疼~");
//等待一秒
yield return new WaitForSeconds(1);
//一秒后变回原来的颜色
Obj.GetComponent<MeshRenderer>().material.color = word1ObjColor;
}
}
|