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

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

 

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

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

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

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

小车前进代码:

public class CarMove : MonoBehaviour
{
public float Speed = 1f; // Start is called before the first frame update
void Start()
{ } // Update is called once per frame
void Update()
{
transform.Translate(Vector3.forward * Speed * Time.deltaTime);
} }

小车转弯代码:

public class CurveCollider : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{ } // Update is called once per frame
void Update()
{ } private void OnCollisionEnter(Collision collision)
{
if (this.CompareTag("TurnLeft"))
{
StartCoroutine(CarTurnLeft(collision));
}
} IEnumerator CarTurnLeft(Collision collision)
{
while (true)
{
Vector3 worldUp = Vector3.up;
Vector3 targetPos = collision.transform.position;
Vector3 direction = transform.position - targetPos;
Vector3 forwardDir = new Vector3(-1.0f, 1.0f, 1.0f);
Vector3.OrthoNormalize(ref worldUp, ref direction, ref forwardDir);
Quaternion quaternion = Quaternion.identity;
quaternion.SetLookRotation(forwardDir);
collision.transform.rotation = quaternion;
yield return null;
Debug.Log(collision.transform.eulerAngles.y);
if (collision.transform.eulerAngles.y >= 270 && (collision.transform.eulerAngles.y - 270) <= 1)
{
quaternion = Quaternion.identity;
quaternion.eulerAngles = new Vector3(0.0f, -90.0f, 0.0f);
collision.transform.rotation = quaternion;
yield break;
}
}
}
}

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

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

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

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

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

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

房子的碰撞代码如下:

private void OnCollisionEnter(Collision collision)
{
if (this.CompareTag(collision.gameObject.tag))
{
GameController.Score++;
}
Destroy(collision.gameObject);
}

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

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

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. 【IDEA】IDEA打开欢迎页面

    概述 IDEA在默认情况下,会进入最后一个项目.如果项目比较大的话会加载的比较久,这个就比较烦人了,目前我觉得最好的办法就是在设置中直接进入欢迎页面. 解决方案 ① 进入设置 ② Appearance ...

  2. WebGPU实现Ray Packet

    大家好~本文在如何用WebGPU流畅渲染百万级2D物体?基础上进行优化,使用WebGPU实现了Ray Packet,也就是将8*8=64条射线作为一个Packet一起去访问BVH的节点.这样做的好处是 ...

  3. C++工厂方法模式讲解和代码示例

    在C++中使用模式 使用示例: 工厂方法模式在 C++ 代码中得到了广泛使用. 当你需要在代码中提供高层次的灵活性时, 该模式会非常实用. 识别方法: 工厂方法可通过构建方法来识别, 它会创建具体类的 ...

  4. 安卓平台RTMP推流或轻量级RTSP服务(摄像头或同屏)编码前数据接入类型总结

    很多开发者在做Android平台RTMP推流或轻量级RTSP服务(摄像头或同屏)时,总感觉接口不够用,以大牛直播SDK为例 (Github) 我们来总结下,我们常规需要支持的编码前音视频数据有哪些类型 ...

  5. KingbaseES 转义字符

    在SQL标准中字符串是用单引号括起来的,在KingbaseES中遵守了该标准,如果在字符串中需要使用到单引号,就需要对其进行转义. 方式一:使用E和反斜杠进行转义 方式二:直接用一个单引号来转义 在K ...

  6. Windows 2019通过网页修改域用户密码

    对于域用户来说,定期修改密码是必须的.对于没有Exchange的组织,而且经常出差在外的人员,能及时修改密码就变得很重要了. 在Windows 2003的时候有iisadmpwd可以修改.但是这个页面 ...

  7. Kubernetes 监控--Grafana

    前面我们使用 Prometheus 采集了 Kubernetes 集群中的一些监控数据指标,我们也尝试使用 promQL 语句查询出了一些数据,并且在 Prometheus 的 Dashboard 中 ...

  8. centos7.2 安装MongoDB

    1.配置阿里云yum仓库 #vim /etc/yum.repos.d/mongodb-org-4.0.repo [mngodb-org] name=MongoDB Repository baseurl ...

  9. Linux安装oracle 12C

    安装虚拟系统CentOS6.5,分配给至少1G的内存,其他条件适当高些,具体参考官方文档 环境准备 vim /etc/profileexport JAVA_HOME=/opt/jdk1.7.0_79e ...

  10. C++ 函数重载解析策略

    参考<C++ Primer Plus>(第6版)中文版,Stephen Prata 著,张海龙 袁国忠译,人民邮电出版社.C++ 使用重载解析策略来决定为函数调用使用哪一个函数定义.重载解 ...