Unity--协程--Coroutine

Unity–协程–Coroutine

1. 协程的基本概念

  1. 基本概念:不是线程,将代码按照划分的时间来执行,这个时间可以是具体的多少秒,也可以是物理帧的时间,也可以是一帧的绘制结束的时间。

  2. 协程的写法:通过返回IEnumerator的函数实现,使用yield return语句暂停执行。

  3. 等待时间:使用WaitForSeconds等待特定时间,在Update和LateUpdate之间执行

  4. 其他等待选项WaitForEndOfFrame等待当前帧结束,可以用来截取画面,游戏帧画面分析WaitForFixedUpdate等待下一个固定物理帧更新时执行。

    下一帧执行: yield return 数字yield return null; 在Update和LateUpdate之间执行

    public IEnumerator MyCoroutine(int i, string str, float t)
    {
          
          
            print(i);
            // 返回值IEumerator yield return 来分时函数,即等待多少秒后继续执行函数
            yield return new WaitForSeconds(5.0f);                // 等待5s后执行
            print(str);
            yield return new WaitForSeconds(3.0f);
            print(t);
            yield return new WaitForEndOfFrame();               // 等待当前帧绘制完毕后执行
            print(t);
            yield return new WaitForFixedUpdate();              // 直到下一个固定更新周期到了执行
            print(i);
        	// ...
    }
    

2. 开启协程

  1. 开启方法:使用StartCoroutine方法。

  2. 开启方式:可以直接传递方法名或先获取IEnumerator对象再传递。

    	// 2.1 不同于文文普通的函数调用来开启协程
        // MyCoroutine(3, "不能使用普通方法调用开启/协程", 5.0f);
        // 2.2 开启方法1
        public void StartMyCoroutine1()
        {
          
          
            StartCoroutine(MyCoroutine(1, "开启协程1", 1.0f));
        }
    
        // 2.3 开启方法2
        public void StartMyCoroutine2()
        {
          
          
            IEnumerator ie =  MyCoroutine(1, "开启协程2", 1.0f);
            StartCoroutine(ie);
        }
        // 2.4 开启多个协程
        public void StartMyCoroutine3()
        {
          
          
            // 开启协程后保留写出对象
            c1 = StartCoroutine(MyCoroutine(1, "多个协程1", 1.0f));
            c2 = StartCoroutine(MyCoroutine(1, "多个协程2", 1.0f));
            c3 = StartCoroutine(MyCoroutine(1, "多个协程3", 1.0f));
           
        }
    

3. 关闭协程

  1. 关闭所有协程:使用StopAllCoroutines

  2. 关闭特定协程:使用StopCoroutine,可以传递IEnumerator对象、协程的引用或方法名。

    	// 1. 关闭所有协程
        public void CloseAllCoroutine()
        {
          
          
            StopAllCoroutines();
        }
    	// 2. 关闭指定协程
        public void CloseSpecialCoroutine()
        {
          
          
            StopCoroutine(c1);
            // StopCoroutine(IEnumerator routine); 通过IEnumerator关闭              
            // StopCoroutine(Coroutine routine);   通过协程名称关闭
            // StopCoroutine(string methodName);   通过协程函数名关闭
        }
    

    关闭指定协程的方法有很多,一般不使用协程函数名关闭

    StopCoroutine(IEnumerator routine); 通过IEnumerator关闭

    StopCoroutine(Coroutine routine); 通过协程名称关闭
    StopCoroutine(string methodName); 通过协程函数名关闭

4. 提前跳出协程

使用yield break在满足条件时提前终止执行。

// 提前跳出协程
    public void BreakCoroutine()
    {
    
    
        IEnumerator MyNewCoroutine()
        {
    
    
            Debug.Log("开始执行协同程序");

            // 执行一些操作
            yield return new WaitForSeconds(1.0f);
            Debug.Log("协同程序执行了一秒");

            // 在这里,我们检查一个条件
            if (SomeCondition())
            {
    
    
                Debug.Log("满足条件,提前结束协同程序");
                yield break; // 提前终止协同程序
            }

            // 如果上面的条件不满足,这将不会执行
            yield return new WaitForSeconds(1.0f);
            Debug.Log("协同程序又执行了一秒");
        }
        StartCoroutine(MyNewCoroutine());

    }
    bool SomeCondition()
    {
    
    
        // 这里是条件的逻辑
        return true; // 例如,始终返回 true 来终止协同程序
    }

5. 特殊情况

协程当组件或游戏对象失效或者失活的时候怎么办???

协程开启后

  1. ​ 组件和物体销毁,协程不执行
  2. ​ 物体失活协程不执行,组件失活协程执行

6.建议

  • 协程的使用:适用于处理异步操作和分步骤执行任务,如动画、加载资源。
  • 性能考虑:比多线程轻量,适合游戏开发中的非阻塞操作。
  • 条件检查:在协程中使用条件检查可以灵活控制流程。
  • 资源管理:在使用协程加载资源时,注意资源的释放和内存管理。

7.完成测试代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CoroutineTest : MonoBehaviour
{
    
    
    Coroutine c1;
    Coroutine c2;
    Coroutine c3;
    // 协程程序
    // 1. 协程的使用
    // 1.1 协程的写法
    public IEnumerator MyCoroutine(int i, string str, float t)
    {
    
    
        print(i);
        // 返回值IEumerator yield return 来分时函数,即等待多少秒后继续执行函数
        yield return new WaitForSeconds(5.0f);              // 等待5s后执行
        print(str);
        yield return new WaitForSeconds(3.0f);
        print(t);
        //yield return new WaitForEndOfFrame();               // 等待当前帧绘制完毕后执行
        //print(t);
        //yield return new WaitForFixedUpdate();              // 直到下一个固定更新周期到了执行
        //print(i);
    }
    // 2. 开启协程
    // 2.1 不同用普通的函数调用来开启协程
    // MyCoroutine(3, "不能使用普通方法调用开启/协程", 5.0f);
    // 2.2 开启方法1
    public void StartMyCoroutine1()
    {
    
    
        StartCoroutine(MyCoroutine(1, "开启协程1", 1.0f));
    }

    // 2.3 开启方法2
    public void StartMyCoroutine2()
    {
    
    
        IEnumerator ie =  MyCoroutine(1, "开启协程2", 1.0f);
        StartCoroutine(ie);
    }
    // 2.4 开启多个协程
    public void StartMyCoroutine3()
    {
    
    
        // 开启协程后保留写出对象
        c1 = StartCoroutine(MyCoroutine(1, "多个协程1", 1.0f));
        c2 = StartCoroutine(MyCoroutine(1, "多个协程2", 1.0f));
        c3 = StartCoroutine(MyCoroutine(1, "多个协程3", 1.0f));
       
    }
    // 3. 关闭协程
    public void CloseAllCoroutine()
    {
    
    
        StopAllCoroutines();
    }
    // 4. 关闭指定协程
    public void CloseSpecialCoroutine()
    {
    
    
        StopCoroutine(c1);
        StopCoroutine(c2);
        StopCoroutine(c3);
        // StopCoroutine(IEnumerator routine); 通过IEnumerator关闭              
        // StopCoroutine(Coroutine routine);   通过协程名称关闭
        // StopCoroutine(string methodName);   通过协程函数名关闭
    }

    // 5. 提前跳出协程
    public void BreakCoroutine()
    {
    
    
        IEnumerator MyNewCoroutine()
        {
    
    
            Debug.Log("开始执行协同程序");

            // 执行一些操作
            yield return new WaitForSeconds(1.0f);
            Debug.Log("协同程序执行了一秒");

            // 在这里,我们检查一个条件
            if (SomeCondition())
            {
    
    
                Debug.Log("满足条件,提前结束协同程序");
                yield break; // 提前终止协同程序
            }

            // 如果上面的条件不满足,这将不会执行
            yield return new WaitForSeconds(1.0f);
            Debug.Log("协同程序又执行了一秒");
        }
        StartCoroutine(MyNewCoroutine());

    }
    bool SomeCondition()
    {
    
    
        // 这里是条件的逻辑
        return true; // 例如,始终返回 true 来终止协同程序
    }
    void Start()
    {
    
    
        StartMyCoroutine1();
        StartMyCoroutine2();
        StartMyCoroutine3();
        CloseSpecialCoroutine();
        BreakCoroutine();
        CloseAllCoroutine();
    }
}

8.应用:计时器(顺序计时和倒计时)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TimeCounter : MonoBehaviour
{
    
    
    IEnumerator TimeConter(int sumSeconds, bool sequence)
    {
    
    
        int time = 0;
        if (sequence)
        {
    
    
            while (true)
            {
    
    
                // 顺序计时
                // 抵达终止时间
                if (time >= sumSeconds)
                {
    
    
                    Debug.Log(sumSeconds + "s 时间到(顺序计时)");
                    yield break;
                }
                // 延迟一秒执行
                yield return new WaitForSeconds(1.0f);
                // 修改时间
                time++;
                // 打印时间
                Debug.Log(time);
            }
        }
        else 
        {
    
    
            // 倒计时
            time = sumSeconds;
            while (true)
            {
    
    
                if (time <= 0)
                {
    
    
                    Debug.Log(sumSeconds + "s 时间到(倒序计时)");
                    yield break;
                }
                Debug.Log(time--);
                yield return new WaitForSeconds(1.0f);
                
            }
        }
    }
    private void Start()
    {
    
    
        // 开启计时器协程
        Coroutine c1 = StartCoroutine(TimeConter(10, true));
        Coroutine c2 = StartCoroutine(TimeConter(3, false));
    }

}

猜你喜欢

转载自blog.csdn.net/qq_40669895/article/details/140084342