千锋教育-做有情怀、有良心、有品质的职业教育机构

手机站
千锋教育

千锋学习站 | 随时随地免费学

千锋教育

扫一扫进入千锋手机站

领取全套视频
千锋教育

关注千锋学习站小程序
随时随地免费学习课程

当前位置:首页  >  技术干货  > 一节课彻底掌握Unity中协程的用法

一节课彻底掌握Unity中协程的用法

来源:千锋教育
发布人:syq
时间: 2022-06-08 13:57:00 1654667820

  文章目录

  一、前言

  二、学习使用协程

  1.首先定义多个定时器,去实现游戏中的逻辑...

  2.案例演示

  3.开启和终止协程

  4.协程的返回值

  5.案例应用

  三、总结

  前言

  协程在Unity开发中非常重要,但注意:协程跟多线程没有任何关系,不要将两者混为一谈,接下来就跟大家分享一下我对协程的理解及用法!

Unity中协程的用法

  一、协程是什么?

  协程是一段在主线程中执行的代码逻辑,协程不是多线程。Unity的协程在每帧结束后去检测yiled的条件是否满足。

  二、学习使用协程

  1.首先定义多个定时器,去实现游戏中的逻辑...

  代码如下:

  float timer1 = 3f;

  float timer2 = 5f;

  float timer3 = 8f;

  void Update()

    {

        timer1 -= Time.deltaTime;

        if (timer1 <= 0)

        {

            Debug.Log("3s过后...");

            timer1 = 3f;

        }

    }

  相信大家都写过类似代码,这种代码如果项目中需要多个定时器时,会显得非常臃肿,并且我们经常忘记做一件事情,比如忘记充值定时器...

  我们都学过循环,for循环中是将变量i定义为局部变量,封装成一个代码块,那我们是否可以将定时器也封装成一个代码块呢?如果可以的话,那么代码应该是这样的:

 for (float timer = 3; timer >= 0; timer -= Time.deltaTime)

        {

            

        }

  现在每一个计时器变量都成为for循环的一部分了,这看上去好多了,而且我不需要去单独设置每一个迭代变量。 但是这段代码放在哪里去执行呢?start?update?显然都不可以,所以恰好协程可以做到这一点。我们回顾一下协程的概念:

  为了能在连续的多帧中(在这个例子中,3秒钟等同于很多帧)调用该方法,Unity必须通过某种方式来存储这个方法的状态,

  -这是通过IEnumerator 中使用yield return语句得到的返回值,当你“yield”一个方法时,你相当于说了,“现在暂停这个方法,

  -然后在下一帧中从这里继续执行!”。

  注意:用0或者null来yield的意思是告诉协程等待下一帧,直到继续执行为止。

  当然,同样的你可以继续yield其他协程,我会在下一个教程中讲到这些。

  代码如下:

    IEnumerator CountDown(){

        for (float timer = 3; timer >= 0; timer -= Time.deltaTime)

        {

            yield return 0;//现在停止这个方法,然后在下一帧中从这里继续执行!

        }

        Debug.Log("3s以后...");

    }

  2.案例演示

  /*

  * 接下来通过实例

  * 1.实现打印5次--我要学游戏开发!

  * 2.实现将这5次输出分到每一帧里去实现:每帧打印1次,共打印5次!

  * 3.每一帧输出“我要学游戏开发!”,无限循环。。。

  通过在一个while循环中使用yield,你可以得到一个无限循环的协程,这几乎就跟一个Update()循环等同。。。

  */

  2.代码如下:

  IEnumerator SayHello5Times()

    {

        for (int i = 0; i < 5; i++)

        {

            Debug.Log("我要学游戏开发!");

            yield return 0;

        }

  3.类似Update,代码如下:

 IEnumerator SayHello5Times()

 {

      while (true)

        {

            //1.输出结果

            Debug.Log("我要学游戏开发!");

            //2.等待下一帧

            yield return 0;

        }

  //1.输出结果

  Debug.Log("我要学游戏开发!");

  //2.等待下一帧

  //3. 这里永远没有机会执行

  }

  但是跟Update()不一样的是,你可以在协程中做一些更有趣的事:

  接下来做一个定时器 每隔几秒完成某一件事

    IEnumerator CountSeconds()

    {

        int seconds = 0;

        while (true)

        {

            for (float timer = 0; timer < 1; timer += Time.deltaTime)

            {

                yield return 0;

            }

            seconds++;

            Debug.Log("自协程启动以来已经过了"+ seconds+"秒");

        }

    }

  这个方法突出了协程一个非常酷的地方:方法的状态被存储了,这使得方法中定义的这些变量都会保存它们的值,即使是在不同的帧中。还记得这个教程开始时那些烦人的计时器变量吗?通过协程,我们再也不需要担心它们了,只需要把变量直接放到方法里面!实际还有更优雅的实现方式!稍后会跟大家讲到。

  3.开启和终止协程

  之前,我们已经学过了通过 StartCoroutine()方法来开始一个协程。

  如果我们想要终止所有的协程,可以通过StopAllCoroutines()方法来实现,

  注意,这只会终止在调用该方法的对象中开始的协程,对于其他的MonoBehavior类中运行的协程不起作用。

  那我们怎么终止其中的一个协程呢?在这个例子里,这是不能的,如果你想要终止某一个特定的协程,

  那么你必须得在开始协程的时候将它的方法名作为字符串,就像这样:

  1、以字符串开启/关闭,缺点:只能有一个参数

        StartCoroutine("FirstTimer");

        StopCoroutine("FirstTimer”);

  2、开启带有参数的协程的两种方式:

        StartCoroutine(Sayhi("hi")) 

        StartCoroutine("Sayhi","hi")

  3、如何终止多个参数的协程呢?接受返回值

    Coroutine stopCor_2 = StartCoroutine(Cor_2());

    StopCoroutine(stopCor_2);

  4、StopAllCoroutines

  5、通知禁用或者销毁方式

      gameObject.SetActive(false); 

      //通过销毁游戏对象方式和禁用同效果

      //Destroy(gameobject)

  4.协程的返回值

  协程一旦被开启后 总是试图将方法内的代码执行完 之后停止

  1.在此之前,我们yield的时候总是用0(或者null),仅仅告诉程序在继续执行前等待下一帧。协程最强大的一个功能就是它们可以通过使用yield语句来相互嵌套。

  2.yield return new WaitForSeconds(n) 表示在n秒后执行后面的代码 但是会收到time.timescale 影响 ,如下代码:

  //隔一定时间完成某件事

    IEnumerator SaySomeThings()

    {

        Debug.Log("协程开始执行");

        yield return StartCoroutine(Wait(1.0f));

        Debug.Log("距离上一条消息已经过去1秒了");

        yield return StartCoroutine(Wait(2.5f));

        Debug.Log("距离上一条消息已经过去2.5秒了");

    }

  上述方法用了yield,但它并没有用0或者null,而是用了Wait()来yield,这相当于是说,“不再继续执行本程序,直到Wait程序结束”。

  等待的方法还可以使用下面方式来实现:

    IEnumerator Wait(float duration)

    {

        for (float timer = 0; timer < duration; timer += Time.deltaTime)

            yield return 0;

    }

  3.在协程内 如果遇到yield return StartCoroutine(test) 剩余的代码将在子协程执行完毕后才能继续执行

  4.如果遇到 yield return new WaitForFixedUpdate 表示剩余代码将在FixedUpdate 执行完毕后执行

  5.如果遇到 yield return WWW 等待一个网络请求完成后继续向下执行

  6.如果遇到 yield return gameObject; 表示在gameobj不为空时向下执行

  5.案例应用

  控制对象行为的例子

  在最后一个例子中,我们就来看看协程如何像创建方便的计时器一样来控制对象行为。协程不仅仅可以使用计数的时间来yield,它还能很巧妙地利用任何条件。将它与嵌套结合使用,你会得到控制游戏对象状态的最强大工具。运动到某一位置,对于下面这个简单脚本组件,我们可以在Inspector面板中给targetPosition和moveSpeed变量赋值,程序运行的时候,该对象就会在协程的作用下,以我们给定的速度运动到给定的位置。

  代码如下:

public Vector3 targetPosition;  

    public float moveSpeed;

    void Start1()

    {

        StartCoroutine(MoveToPosition(targetPosition));

    }

 

    IEnumerator MoveToPosition(Vector3 target)

    {

        while (transform.position != target)

        {

            transform.position = Vector3.MoveTowards(transform.position, target, moveSpeed * Time.deltaTime);

            yield return 0;

        }

    }

  这样,这个程序并没有通过一个计时器或者无限循环,而是根据对象是否到达指定位置来yield。

  我们可以让运动到某一位置的程序做更多,不仅仅是一个指定位置,我们还可以通过数组来给它赋值更多的位置,通过MoveToPosition() ,我们可以让它在这些点之间持续运动。

  代码如下:

 public Vector3[] path;  

 

    void Start2()

    {

        StartCoroutine(MoveOnPath(true));

    }

 

    IEnumerator MoveOnPath(bool loop)

    {

        do

        {

            foreach (var point in path)

                yield return StartCoroutine(MoveToPosition(point));

        }

        while (loop);

    }

  还可以加一个布尔变量,你可以控制在对象运动到最后一个点时是否要进行循环。

  课堂练习:尝试让物体在某个点停留3s

  如果把Wait()程序加进来,这样就能让我们的对象在某个点就可以选择是否暂停下来,就像一个正在巡逻的AI守卫一样,并且这种实现方式看起来非常优雅!

  三、总结

  l 多个协程可以同时运行,它们会根据各自的启动顺序来更新;

  l 协程可以嵌套任意多层(在这个例子中我们只嵌套了一层);

  l 如果你想让多个脚本访问一个协程,那么你可以定义静态的协程;

  l 协程不是多线程(尽管它们看上去是这样的),它们运行在同一线程中,跟普通的脚本一样;

  l 如果你的程序需要进行大量的计算,那么可以考虑在一个随时间进行的协程中处理它们;

  l IEnumerator类型的方法不能带ref或者out型的参数,但可以带被传递的引用;

  l 协程有多种开启和终止的方法,但是最好用哪种方式开启,就是用哪种方式终止。

  更多关于“Unity”的问题,欢迎咨询千锋教育在线名师。千锋教育多年办学,课程大纲紧跟企业需求,更科学更严谨,每年培养泛IT人才近2万人。不论你是零基础还是想提升,都可以找到适合的班型,千锋教育随时欢迎你来试听。

tags:
声明:本站稿件版权均属千锋教育所有,未经许可不得擅自转载。
10年以上业内强师集结,手把手带你蜕变精英
请您保持通讯畅通,专属学习老师24小时内将与您1V1沟通
免费领取
今日已有369人领取成功
刘同学 138****2860 刚刚成功领取
王同学 131****2015 刚刚成功领取
张同学 133****4652 刚刚成功领取
李同学 135****8607 刚刚成功领取
杨同学 132****5667 刚刚成功领取
岳同学 134****6652 刚刚成功领取
梁同学 157****2950 刚刚成功领取
刘同学 189****1015 刚刚成功领取
张同学 155****4678 刚刚成功领取
邹同学 139****2907 刚刚成功领取
董同学 138****2867 刚刚成功领取
周同学 136****3602 刚刚成功领取
相关推荐HOT