为什么说是诡异的协程呢?首先从一个案例说起吧,示例如下:

游戏目标:让小车进入到对应颜色屋子里,即可获得一分。(转弯的道路可控)

 

为了让小车能够平滑转弯,小车的前进方向需要和车子的位置与圆心组成的连线垂直。

首先想到的就是在车子进入到碰撞体和在碰撞体里面都是上述运动方式,离开碰撞体后相当于旋转了90度。

但是当车子在转弯的道路上时,此时将左转弯的路变成右转弯的路,车子就会失控,因为碰撞体消失后对应的事件就不会执行了。

所以想到让车子持续转弯的方法放进协程里面做,小车前进代码和转弯代码如下:

小车前进代码:

  1. public class CarMove : MonoBehaviour
  2. {
  3. public float Speed = 1f;
  4.  
  5. // Start is called before the first frame update
  6. void Start()
  7. {
  8.  
  9. }
  10.  
  11. // Update is called once per frame
  12. void Update()
  13. {
  14. transform.Translate(Vector3.forward * Speed * Time.deltaTime);
  15. }
  16.  
  17. }

小车转弯代码:

  1. public class CurveCollider : MonoBehaviour
  2. {
  3. // Start is called before the first frame update
  4. void Start()
  5. {
  6.  
  7. }
  8.  
  9. // Update is called once per frame
  10. void Update()
  11. {
  12.  
  13. }
  14.  
  15. private void OnCollisionEnter(Collision collision)
  16. {
  17. if (this.CompareTag("TurnLeft"))
  18. {
  19. StartCoroutine(CarTurnLeft(collision));
  20. }
  21. }
  22.  
  23. IEnumerator CarTurnLeft(Collision collision)
  24. {
  25. while (true)
  26. {
  27. Vector3 worldUp = Vector3.up;
  28. Vector3 targetPos = collision.transform.position;
  29. Vector3 direction = transform.position - targetPos;
  30. Vector3 forwardDir = new Vector3(-1.0f, 1.0f, 1.0f);
  31. Vector3.OrthoNormalize(ref worldUp, ref direction, ref forwardDir);
  32. Quaternion quaternion = Quaternion.identity;
  33. quaternion.SetLookRotation(forwardDir);
  34. collision.transform.rotation = quaternion;
  35. yield return null;
  36. Debug.Log(collision.transform.eulerAngles.y);
  37. if (collision.transform.eulerAngles.y >= 270 && (collision.transform.eulerAngles.y - 270) <= 1)
  38. {
  39. quaternion = Quaternion.identity;
  40. quaternion.eulerAngles = new Vector3(0.0f, -90.0f, 0.0f);
  41. collision.transform.rotation = quaternion;
  42. yield break;
  43. }
  44. }
  45. }
  46. }

下面先简单介绍一下协程的基本概念:Unity手册:协程
UnityEngine所提供的SDK都只能在单线程中调用,而协程也是单线程的,不同于多线程。

Unity中只代码只要有一个地方代码出现死循环或者运行时间较长,游戏就会卡死。

关于协程其中有这么一句话,很重要:协程优化

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

好了,现在回到我们的案例,发生了什么问题呢?

当其中一个小车进入到房子后,其中有一个小车没有正常转弯了,并且发生报错,如上图标红的地方,这是为什么呢?

房子的碰撞代码如下:

  1. private void OnCollisionEnter(Collision collision)
  2. {
  3. if (this.CompareTag(collision.gameObject.tag))
  4. {
  5. GameController.Score++;
  6. }
  7. Destroy(collision.gameObject);
  8. }

当小车进入到房子后就会摧毁小车,如果进入的车是对的,就加一分。

报错的行43行是如下代码:

  1. if (collision.transform.eulerAngles.y >= 270 && (collision.transform.eulerAngles.y - 270) <= 1) 

这是不是很匪夷所思呢?

因为当小车进入直线轨道时协程已经结束了,怎么协程还在运行呢?

此时你可以想起上面那句话,应该可以猜到了为什么会发生这样。

当Car1进入House碰撞体时,也将Collider存放在同一个地方,之后将这个小车摧毁。

此时小车3正好在执行协程,当从yield 之后的语句开始执行时,由于小车已经被摧毁,所以就报错了。

Unity之"诡异"的协程的更多相关文章

  1. 【Unity优化】如何实现Unity编辑器中的协程

    Unity编辑器中何时需要协程 当我们定制Unity编辑器的时候,往往需要启动额外的协程或者线程进行处理.比如当执行一些界面更新的时候,需要大量计算,如果用户在不断修正一个参数,比如从1变化到2,这种 ...

  2. Unity脚本编程之——协程(Coroutine)

    本文翻译自Unity官方文档:https://docs.unity3d.com/Manual/Coroutines.html 专有名词: Coroutine 协程 Alpha 不透明度 当你调用一个函 ...

  3. Unity中巧用协程和游戏对象的生命周期处理游戏重启的问题

    主要用到协程(Coroutines)和游戏对象的生命周期(GameObject Lifecycle)基础知识,巧妙解决了游戏重启的问题. 关于协程,这里有篇文章我觉得写的非常好,理解起来也很容易.推荐 ...

  4. 【Unity优化】怎样实现Unity编辑器中的协程

    Unity编辑器中何时须要协程 当我们定制Unity编辑器的时候,往往须要启动额外的协程或者线程进行处理.比方当运行一些界面更新的时候,须要大量计算,假设用户在不断修正一个參数,比方从1变化到2.这种 ...

  5. 【Unity笔记】使用协程(Coroutine)异步加载场景

    using UnityEngine; using System.Collections; using UnityEngine.SceneManagement; using System; public ...

  6. Unity带参数的协程

    两种方法都可以传递参数,代码如下: using UnityEngine; using System.Collections; public class Test : MonoBehaviour { v ...

  7. Unity协程(Coroutine)原理深入剖析

    Unity协程(Coroutine)原理深入剖析 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com 其实协程并没有那么复杂,网上很多地方都说是多 ...

  8. Unity协程(Coroutine)原理深入剖析(转载)

    记得去年6月份刚开始实习的时候,当时要我写网络层的结构,用到了协程,当时有点懵,完全不知道Unity协程的执行机制是怎么样的,只是知道函数的返回值是IEnumerator类型,函数中使用yield r ...

  9. [Unity菜鸟] 协程Coroutine

    1.协程,即协作式程序,其思想是,一系列互相依赖的协程间依次使用CPU,每次只有一个协程工作,而其他协程处于休眠状态. unity中StartCoroutine()就是协程,协程实际上是在一个线程中, ...

随机推荐

  1. 【HTML】学习路径5-预格式标签和字体标签

    <!DOCTYPE html> <html> <head> <title>我是标题</title> <meta charset=&qu ...

  2. ifort + mkl + impi (全套intel)编译安装量子化学软件GAMESS 2022 R1版本

    说明:linux下编译软件都需要先配置好该软件依赖的系统环境.系统环境可以通过软件的安装说明了解,例如:readme.md等文件或网页.这个前提条件很重要!后面正式编译出错基本都可以归结到系统环境配置 ...

  3. Spark 读 Hbase

    package com.grady import org.apache.hadoop.hbase.HBaseConfiguration import org.apache.hadoop.hbase.c ...

  4. [Python]-openpyxl模块Excel数据处理-读取公式的结果

    日常需要Python来处理各种数据,处理Excel数据常用的库一般有openpyxl.xlrd(读取).xlwt(写入). 经过对比发现openpyxl模块比较好用. openpyxl模块 这篇笔记比 ...

  5. 使用mbr2gpt将MBR磁盘转换为GPT磁盘

    随着越来越多的新PC的到来,UEFI启动渐渐的取代了BIOS启动方式.不过UEFI需要从GPT磁盘启动,原来的MBR磁盘不行.如果你更换了硬件,只想把磁盘拿到新平台上用又不想重装系统的话就麻烦了.以前 ...

  6. 使用J2EE 登录实例开发

    我们先了解下Servlet的生命周期 Servlet部署在容器里,其生命周期由容器管理. 概括为以下几个阶段: 1)容器加载Servlet类. 当第一次有Web客户请求Servlet服务或当Web服务 ...

  7. vscode调试thinkhphp

    第一步先安装xdebug扩展,我用宝塔环境,所以一键安装 第二步.在vscode中安装插件 我的php.ini是这样的 xdebug.remote_enable = 1 xdebug.remote_a ...

  8. Nginx缓存了DNS解析造成后端不通--代理

    文章转载自:https://segmentfault.com/a/1190000022365954 1 问题现象 我们使用 Nginx 的时候,经常会用到 Proxy 功能,为了方便管理,后端站点或者 ...

  9. Elasticsearch准实时索引实现(数据写入到es分片并存储到文件中的过程)

    溢写到文件系统缓存 当数据写入到ES分片时,会首先写入到内存中,然后通过内存的buffer生成一个segment,并刷到文件系统缓存中,数据可以被检索(注意不是直接刷到磁盘) ES中默认1秒,refr ...

  10. python-数据描述与分析(1)

    数据描述与分析 在进行数据分析之前,我们需要做的事情是对数据有初步的了解,这个了解就涉及对行业的了解和对数据本身的敏感程度,通俗来说就是对数据的分布有大概的理解,此时我们需要工具进行数据的描述,观测数 ...