首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Unity3D协程的使用

Unity3D协程的使用

作者头像
心疼你的一切
发布2026-01-20 14:11:27
发布2026-01-20 14:11:27
760
举报
文章被收录于专栏:人工智能人工智能

前言

记录一下协程怎么使用的 如果觉得本篇文章有用别忘了点个关注,关注不迷路,持续分享更多Unity干货文章。

提示:以下是本篇文章正文内容,下面案例可供参考

一、协程是什么?

协程就相当于C#的线程。

Unity3D是支持多线程的,只是线程不能访问主线程中的对象,虽然说线程不能访问主线程中的对象,但是可以将一些复杂的算法计算、网络连接等逻辑抛给一个线程去处理,将处理的数据放到公共的内存模块中。Unity3D主线程就可以使用了。

那么协程是什么呢,协程就是Unity针对上面的问题提出的解决方案,协程又叫做协同程序,使用的场景主要有资源、场景的异步加载,但是可以访问主线程中的对象。

协程的本质是迭代器,能够暂停协程执行,暂停后立即返回主函数,执行主函数剩余的部分,直到中断执行完成后,从中断指令的下一行继续执行协程剩余的函数,函数全部执行完成,协程结束。由于中断执行的出现,可以将一个函数分割成多个帧中去执行

二、协程的原理

协程中的所有初始代码,从协程开始到中断执行的位置,可以中断,协程代码中的其他部分,也就是中断执行后面的代码将出现在Unity主循环DelayeCallManager中。

协程由 C# 编译器自动生成的类实例提供支持。

此对象用于跟踪单个方法的多次调用之间的协程状态。

因为协程中的局部作用域变量必须在 yield 调用中保持一致,所以这些局部作用域变量将被保存到上一级的生成的它们的类中,从而保证在协程的存活期内保留在堆上的地址分配。

该对象还会跟踪协程的内部状态:它会记住协程暂停后必须从代码中的哪一点恢复。

因此,启动协程引起的内存压力等于固定开销成本加上其局部变量的消耗。

启动协程的代码将构造并调用此对象,然后 Unity 的DelayedCallManager在每当满足协程的暂停条件时再次调用此对象。

由于协程通常在其他协程之外启动,因此它们的执行成本将分担到上述两个位置,这两个位置又叫做协程函数和协程调度器。

2-1. 协程的实现

代码如下

代码语言:javascript
复制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Coroutine_IEmator : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("协程之前执行的打印");
        StartCoroutine(enumerator());
        Debug.Log("协程之后执行的打印");
    }
    public IEnumerator enumerator()
    {
        Debug.Log("开始协程了");
        yield return new WaitForSeconds(2f);  //等待2秒
        Debug.Log("等了两秒之后的打印");
    }
  
}

2-2 效果如下

在这里插入图片描述
在这里插入图片描述

PS:这个例子演示了,协程的执行顺序,协程的写法,协程的调用

协程写法: (1)声明是IEnumerator 迭代器类型返回值 (2)返回值为yield return new,也就是中断程序,就跟int的返回值是0123一样,没有返回值会报错 (3)执行中断程序后面的函数

2-3 协程的返回值

在这里插入图片描述
在这里插入图片描述

2-4 协程的调用

代码语言:javascript
复制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Coroutine_IEmator : MonoBehaviour
{
    private void Awake()
    {
        //协程的调用如下
        //调用协程使用StartCoroutine(m_Ien());
        //调用协程还可以这么写StartCoroutine(“m_Ien”);
        //终止协程用StopCoroutine(m_Ien());
        //终止协程还可以这么写StopCoroutine(“m_Ien”);
        //声明协程再终止协程,mCoroutine = StartCoroutine(m_Ien()); StopCoroutine(mCoroutine);
        //终止所有协程StopAllCoroutines();

        //StartCoroutine("enumerator");  //这种开启协程可以终止
        //StopCoroutine("enumerator");   //可以终止

        StartCoroutine(enumerator()); //这种开启协程终止不了
        StopCoroutine(enumerator()); //终止不了
    }
    // Start is called before the first frame update
    void Start()
    {
        //Debug.Log("协程之前执行的打印");
        ////StartCoroutine(enumerator());
        //Debug.Log("协程之后执行的打印");
    }
    public IEnumerator enumerator()
    {
        Debug.Log("开始协程了");
        yield return new WaitForSeconds(2f);  //等待2秒
        Debug.Log("等了两秒之后的打印");
    }
}

2-5 协程提供的延迟的类有下列几种

在这里插入图片描述
在这里插入图片描述

2-6 重写 WaitForSeconds

代码如下

代码语言:javascript
复制
/// <summary>
/// 任务扩展
/// </summary>
public static class TaskExtendC
{
    static public IEnumerator WaitForSeconds(float second)
    {
        DateTime init_dt = DateTime.Now;
        TimeSpan time;
        while (true)
        {
            time = DateTime.Now - init_dt;
            if (time.TotalSeconds <= second)
            {
                yield return null;
            }
            else
            {
                break;
            }
        }
    }
}

调用的方法和unity差不多

在这里插入图片描述
在这里插入图片描述

如果超时或者符合某种条件就继续执行怎么改动呢?

2-7 超时处理或某种条件执行

代码如下

代码语言:javascript
复制
/// <summary>
/// 超时扩展 
/// 加了一个回调,每次都检查是否为true,true则等待 
/// </summary>
static class TaskExtendCC
{
    public delegate bool CondDelegate();
    static public IEnumerator WaitForSeconds(float second, CondDelegate cond = null)
    {
        DateTime init_dt = DateTime.Now;
        TimeSpan time;
        while (true)
        {
            time = DateTime.Now - init_dt;
            if (time.TotalSeconds <= second && !cond())
            {
                yield return null;
            }
            else
            {
                break;
            }
        }
    }
}

2-8 yield return Coroutine 协程执行完毕后执行后面代码

示例如下

代码语言:javascript
复制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class WaitForEndOfAni : IEnumerator
{
    AnimationState m_animState;

    public WaitForEndOfAni(AnimationState animState)
    {
        m_animState = animState;
    }
    //=> throw new System.NotImplementedException();
    public object Current {

        get
        {
            return null;
        }

    } 

    public bool MoveNext()
    {
      return m_animState.enabled;
    }

    public void Reset()
    {
       
    } 
}

核心代码就是判断 m_animState.enabled 是否播放完成 测试代码如下

代码语言:javascript
复制
 IEnumerator DoTest()
    {
 
        Animation anim = GetComponentInChildren<Animation>();
        AnimationState animAttack = anim["attack"];
        animAttack.speed = 0.1f;
 
        AnimationState animHit = anim["hit"];
        animHit.speed = 0.1f;
 
        AnimationState animDie = anim["die"];
        animDie.speed = 0.1f;
 
        Debug.Log("1.开始播放攻击动画。" + Time.time * 1000);
        anim.Play(animAttack.name);
        yield return StartCoroutine(new WaitForEndOfAnim(animAttack));
 
        Debug.Log("2.开始播放受击动画。" + Time.time * 1000);
        anim.Play(animHit.name);
        yield return StartCoroutine(new WaitForEndOfAnim(animHit));
 
        Debug.Log("3.开始播放死亡动画。" + Time.time * 1000);
        anim.Play(animDie.name);
        yield return StartCoroutine(new WaitForEndOfAnim(animDie));
    }

总结

这篇文章详细讲解了Unity3D的协程的原理以及使用。

以及重写协程程序的返回值和自定义协程返回值。

对于某些代码来说难度比较高,推荐多理解多练习。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-11-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、协程是什么?
  • 二、协程的原理
    • 2-1. 协程的实现
    • 2-2 效果如下
    • 2-3 协程的返回值
    • 2-4 协程的调用
    • 2-5 协程提供的延迟的类有下列几种
    • 2-6 重写 WaitForSeconds
    • 2-7 超时处理或某种条件执行
    • 2-8 yield return Coroutine 协程执行完毕后执行后面代码
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档