Unity之"诡异"的协程
为什么说是诡异的协程呢?首先从一个案例说起吧,示例如下:
游戏目标:让小车进入到对应颜色屋子里,即可获得一分。(转弯的道路可控)

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

首先想到的就是在车子进入到碰撞体和在碰撞体里面都是上述运动方式,离开碰撞体后相当于旋转了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之"诡异"的协程的更多相关文章
- 【Unity优化】如何实现Unity编辑器中的协程
Unity编辑器中何时需要协程 当我们定制Unity编辑器的时候,往往需要启动额外的协程或者线程进行处理.比如当执行一些界面更新的时候,需要大量计算,如果用户在不断修正一个参数,比如从1变化到2,这种 ...
- Unity脚本编程之——协程(Coroutine)
本文翻译自Unity官方文档:https://docs.unity3d.com/Manual/Coroutines.html 专有名词: Coroutine 协程 Alpha 不透明度 当你调用一个函 ...
- Unity中巧用协程和游戏对象的生命周期处理游戏重启的问题
主要用到协程(Coroutines)和游戏对象的生命周期(GameObject Lifecycle)基础知识,巧妙解决了游戏重启的问题. 关于协程,这里有篇文章我觉得写的非常好,理解起来也很容易.推荐 ...
- 【Unity优化】怎样实现Unity编辑器中的协程
Unity编辑器中何时须要协程 当我们定制Unity编辑器的时候,往往须要启动额外的协程或者线程进行处理.比方当运行一些界面更新的时候,须要大量计算,假设用户在不断修正一个參数,比方从1变化到2.这种 ...
- 【Unity笔记】使用协程(Coroutine)异步加载场景
using UnityEngine; using System.Collections; using UnityEngine.SceneManagement; using System; public ...
- Unity带参数的协程
两种方法都可以传递参数,代码如下: using UnityEngine; using System.Collections; public class Test : MonoBehaviour { v ...
- Unity协程(Coroutine)原理深入剖析
Unity协程(Coroutine)原理深入剖析 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com 其实协程并没有那么复杂,网上很多地方都说是多 ...
- Unity协程(Coroutine)原理深入剖析(转载)
记得去年6月份刚开始实习的时候,当时要我写网络层的结构,用到了协程,当时有点懵,完全不知道Unity协程的执行机制是怎么样的,只是知道函数的返回值是IEnumerator类型,函数中使用yield r ...
- [Unity菜鸟] 协程Coroutine
1.协程,即协作式程序,其思想是,一系列互相依赖的协程间依次使用CPU,每次只有一个协程工作,而其他协程处于休眠状态. unity中StartCoroutine()就是协程,协程实际上是在一个线程中, ...
随机推荐
- HDU 5362 Just A String 指数型母函数
题面 Description 用m种字母构造一个长度为n的字符串,如果一个字符串的字母重组后可以形成一个回文串则该串合法,问随机构成的长为n的字符串的合法子串数目期望值. Input 第一行一整数T表 ...
- WAF对抗-安全狗(联合查询篇)
WAF对抗-安全狗(联合查询篇) 实验环境 网站安全狗APACHE版V4.0.靶场:dvwa 为了方便对比可以在这个在线靶场申请一个dvwa https://www.vsplate.com/ mysq ...
- 【MySQL】从入门到掌握2-下载安装
上期:[MySQL]从入门到掌握1-一些背景知识 第一章:下载 官网下载地址: https://dev.mysql.com/downloads/mysql/ https://dev.mysql.com ...
- 【java】学习路径19-Math类、BigDecimal的使用
1--Math类简单的东西 //一些常数 show(Math.PI); show(Math.E); //四舍五入 show(Math.round(3.4)); show(Math.round(3.6) ...
- 057_末晨曦Vue技术_处理边界情况之强制更新和创建低开销的静态组件
强制更新和创建低开销的静态组件 点击打开视频讲解更加详细 强制更新 如果你发现你自己需要在 Vue 中做一次强制更新,99.9% 的情况,是你在某个地方做错了事. 你可能还没有留意到数组或对象的变更检 ...
- KingbaseES wal(xlog) 日志清理故障恢复案例
案例说明: 在通过sys_archivecleanup工具手工清理wal日志时,在control文件中查询的检查点对应的wal日志是"000000010000000000000008&quo ...
- [Python]-字典-实践经验总结
字典是Python中常用的一个数据类型. 与列表有相似的用法,表现在列表的下标和字典的键值可以通过相似的方式读取数据: list_name[0] = value dict_name['key'] = ...
- 基于OpenHarmony的智能喝水提醒器
一.硬件说明 Neptune OpenHarmony物联网IOT模组Wi-Fi&蓝牙双模开发板.超声波模块.蜂鸣器模块.杜邦线若干 开发板相关资料:https://gitee.com/hiho ...
- X-Pack:创建阈值检查警报
简单的事情应该简单(Simple things should be simple),这是Elastic {ON} '17的主题之一,Elastics收到了许多关于使用简单易用的UI创建警报的请求.事实 ...
- 在K8S中安装jenkins
以 NFS 为存储卷的示例,将在 NFS 存储卷上创建 Jenkins 目录,然后创建 NFS 类型的 PV.PVC. 1.NFS 存储卷创建 Jenkins 目录 进入 NFS Server 服务器 ...