Unity之"詭異"的協程

為什么說是詭異的協程呢?首先從一個案例說起吧,示例如下:
游戲目標:讓小車進入到對應顏色屋子里,即可獲得一分 。(轉彎的道路可控)

Unity之"詭異"的協程

文章插圖
 
Unity之"詭異"的協程

文章插圖
為了讓小車能夠平滑轉彎,小車的前進方向需要和車子的位置與圓心組成的連線垂直 。
Unity之"詭異"的協程

文章插圖
首先想到的就是在車子進入到碰撞體和在碰撞體里面都是上述運動方式,離開碰撞體后相當于旋轉了90度 。
但是當車子在轉彎的道路上時,此時將左轉彎的路變成右轉彎的路,車子就會失控,因為碰撞體消失后對應的事件就不會執行了 。
所以想到讓車子持續轉彎的方法放進協程里面做,小車前進代碼和轉彎代碼如下:
小車前進代碼:
public class CarMove : MonoBehaviour{public float Speed = 1f;// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){transform.Translate(Vector3.forward * Speed * Time.deltaTime);}}小車轉彎代碼:
public class CurveCollider : MonoBehaviour{// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid 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 調用中保持一致,所以這些局部作用域變量將被保存到上一級的生成的它們的類中,從而保證在協程的存活期內保留在堆上的地址分配 。
好了,現在回到我們的案例,發生了什么問題呢?
Unity之&quot;詭異&quot;的協程

文章插圖

Unity之&quot;詭異&quot;的協程

文章插圖
當其中一個小車進入到房子后,其中有一個小車沒有正常轉彎了 , 并且發生報錯,如上圖標紅的地方,這是為什么呢?
房子的碰撞代碼如下:
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) 這是不是很匪夷所思呢?
因為當小車進入直線軌道時協程已經結束了,怎么協程還在運行呢?
此時你可以想起上面那句話,應該可以猜到了為什么會發生這樣 。
Unity之&quot;詭異&quot;的協程

文章插圖
當Car1進入House碰撞體時,也將Collider存放在同一個地方,之后將這個小車摧毀 。
此時小車3正好在執行協程,當從yield 之后的語句開始執行時,由于小車已經被摧毀,所以就報錯了 。
【Unity之"詭異"的協程】

    推薦閱讀