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

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

 

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

首先想到的就是在车子进入到碰撞体和在碰撞体里面都是上述运动方式,离开碰撞体后相当于旋转了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. Spring 14: Spring + MyBatis初步整合开发

    SM整合步骤 预期项目结构 新建数据库和数据表 springuser.sql脚本如下 create database ssm; use ssm; create table users( userid ...

  2. Prometheus教程

    Prometheus介绍 主要特征 使用时间序列数据(tsdb)的多维度数据模型 灵活的查询语言(PromQL) 不依赖分布式存储,单个节点是自主的 通过http请求拉取(pull)时间序列数据(ts ...

  3. SUSE Linux Enterprise Server 12 使用二进制文件安装docker

    Docker-CE in SUSE 虽然使用zypper添加源也能安装,不过我在SLES 12sp5 上安装时发现好多命令还需要自己手动软连接,干脆网上找了找文档,再自己小改下,用二进制部署,也是可以 ...

  4. Linux_etc-passwd文件总结

    文件内容 ## # User Database # # Note that this file is consulted directly only when the system is runnin ...

  5. 1.关于433MHz按键单片机解码

    近段时间做项目要用到单片机接收433MHz按键发过来的码值,涉及短按.连按.长按,由于之前没有做过这方面一开始有点蒙,找遍网上都没有案例,现在项目完成了整理自己的一些心得和大家分享分享!!!直入主题. ...

  6. Rust-语句和表达式

    语句和表达式 Rust 的函数体是由一系列语句组成,最后由一个表达式来返回值,例如: fn add_with_extra(x: i32, y: i32) -> i32 { let x = x + ...

  7. 1.nexus的安装

    1,Nexus 介绍 Nexus是什么 Nexus 是一个强大的maven仓库管理器,它极大地简化了本地内部仓库的维护和外部仓库的访问. 不仅如此,他还可以用来创建yum.pypi.npm.docke ...

  8. MySQL学习(1)---MySQL概述

    什么是数据库 概述 数据库(Database)是长期存储在计算机内有组织.大量.共享的数据集合.它可以供各种用户共享,具有最小冗余度和较高的数据独立性.数据库管理系统DBMS(Database Man ...

  9. Mysql三种日志(binlog,redolog,undolog)的作用和区别

    Mysql有三种很重要的日志也是面试经常涉及到的考点,分别是 binlog .redo log和undo log, 这里面binlog 是server层实现的日志,而redo log 和undo lo ...

  10. 引入Wukong让你的系统瞬间具备IOC能力

    [Github源码] 本文重点要说的是如何通过引入Wukong第三方包让自己的系统能够拥有IOC容器能力,但在具体讲解步骤之前,还是想先简单的介绍一下什么是IOC以及它存在的意义:同时也就能清楚Wuk ...