协程不会让步

Coroutine Won't Yield

我想不通为什么这个协程不会让步。

这段代码...

while(angle > 1.0f)
        {
            my_transform.rotation = Quaternion.Slerp(my_transform.rotation, fwdRotation, Time.deltaTime * 2.0f);
            angle = Quaternion.Angle(my_transform.rotation, fwdRotation);
            Debug.Log ("Inside loop" + angle);
            yield return null;
        }

...不会屈服。它只是通过它。我知道它确实如此,因为在 运行 时间里,我一帧一帧地玩游戏,我可以看到这行代码...

yield return StartCoroutine(MoveBall(col));
        rigidbody.WakeUp();  <<<<<<-------THIS ONE RIGHT HERE

...旋转调整完成前执行。为什么会发生这种情况?

using UnityEngine;
using System.Collections;

public class EmptyBall : MonoBehaviour
{
    public Ball.BallTypes this_ball_type;
    public PlayerCharacter this_player;
    public AudioClip capture_attempt;
    public AudioClip attempting_capture;
    public AudioClip capture_success;
    public AudioClip capture_fail;
    public GameObject capture_orb_prefab;

    private Transform my_transform;
    private RaycastHit hit;
    private float distance_to_ground;
    private CalculateCapture calculate_capture_script = new CalculateCapture();

    void Start()
    {
        my_transform = transform;
    }
    void Update()
    {
        if(Physics.Raycast(transform.position, -Vector3.up, out hit)){
            distance_to_ground = hit.distance;
        }
    }
    void OnCollisionEnter(Collision col)
    {
        if(col.gameObject.tag == "Capturable")
        {
            Monster this_monster = col.gameObject.GetComponent<Monster>();
            if(!this_monster.is_captured)
            {
                audio.PlayOneShot(capture_attempt);
                col.gameObject.GetComponent<Animation>().enabled = false;
                StartCoroutine(Capture(col));
            }
            else
            {

            }
        }
        else
        {
            Destroy(this.gameObject);
        }
    }

    private IEnumerator Capture(Collision col)
    {
        yield return StartCoroutine(MoveBall(col));
        rigidbody.WakeUp();
        while(distance_to_ground > 0.2f)
        {
            yield return null;
        }
        rigidbody.isKinematic = true;
        yield return StartCoroutine(TryToCatch(col));
    }
    private IEnumerator MoveBall(Collision col)
    {
        Vector3 move_to = new Vector3(transform.position.x-1.5f, col.contacts[0].point.y+1.5f, transform.position.z-1.5f);
        while(Vector3.Distance(transform.position, move_to) > 0.01f)
        {
            rigidbody.velocity = Vector3.zero;
            rigidbody.angularVelocity = Vector3.zero;
            rigidbody.Sleep();
            transform.LookAt(col.transform.position);
            transform.position = Vector3.Lerp(transform.position, move_to, 5f * Time.deltaTime);
            yield return null;
        }
        animation["Open_Top"].speed = 5;
        animation.Play("Open_Top");
        GameObject orb = Instantiate(capture_orb_prefab, col.gameObject.GetComponentInChildren<Renderer>().renderer.bounds.center, Quaternion.identity) as GameObject;
        col.gameObject.SetActive(false);
        while(Vector3.Distance(my_transform.position, orb.transform.position) > 0.01f)
        {
            Vector3 orb_target = new Vector3(my_transform.position.x, my_transform.position.y, my_transform.position.z);
            orb.transform.position = Vector3.Lerp(orb.transform.position, orb_target, 2.7f * Time.deltaTime);
            yield return null;
        }
        orb.transform.parent = my_transform;
        animation["Close_Top"].speed = -5f;
        animation["Close_Top"].time = animation["Close_Top"].length;
        animation.Play("Close_Top");
        Vector3 flatFwd = new Vector3(my_transform.forward.x, 0, my_transform.forward.z);
        Quaternion fwdRotation = Quaternion.LookRotation(flatFwd, Vector3.up);
        float angle = Quaternion.Angle(my_transform.rotation, fwdRotation);
        Debug.Log (angle);
        while(angle > 1.0f)
        {
            my_transform.rotation = Quaternion.Slerp(my_transform.rotation, fwdRotation, Time.deltaTime * 2.0f);
            angle = Quaternion.Angle(my_transform.rotation, fwdRotation);
            Debug.Log ("Inside loop" + angle);
            yield return null;
        }
        Destroy(orb);
        yield return null;
    }
    private IEnumerator TryToCatch(Collision col)
    {
        Monster this_monster = col.gameObject.GetComponent<Monster>();
        audio.PlayOneShot(attempting_capture);
        yield return new WaitForSeconds(attempting_capture.length+1);
        bool try_to_capture = calculate_capture_script.AttemptCapture(this_monster.status_condition, this_ball_type, this_monster.cur_hp,
                                                                      this_monster.cur_max_hp, this_monster.capture_rate);
        if(try_to_capture){
            this_monster.is_captured = true;
            this_monster.trainers_name = this_player.players_name;
            Monster temp = this_monster;
            PlayerMonsterData data_holder_monster = new PlayerMonsterData (temp.is_setup, temp.is_captured, temp.trainers_name, temp.monster_name,
                                                                                temp.nick_name,
                                                                                temp.is_from_trade, temp.level, temp.gender, temp.nature, temp.max_hp,
                                                                                temp.cur_max_hp, temp.max_atk, temp.max_def, temp.max_spatk, temp.max_spdef,
                                                                                temp.max_spd, temp.cur_hp, temp.cur_atk, temp.cur_def, temp.cur_spatk,
                                                                                temp.cur_spdef, temp.cur_spd, temp.last_required_exp, temp.current_exp,
                                                                                temp.next_required_exp);
            if(this_player.players_monster_roster.Count < 6)
            {
                this_player.players_monster_roster.Add(data_holder_monster);
            }
            else
            {
                this_player.players_monster_inventory.Add(data_holder_monster);
            }
            this_monster.is_captured = false;
            this_monster.SetDead();
            audio.PlayOneShot(capture_success);
            yield return new WaitForSeconds(capture_success.length);
        }
        else
        {
            animation["Open_Top"].speed = 5;
            animation.Play("Open_Top");
            audio.PlayOneShot(capture_fail);
            yield return new WaitForSeconds(animation["Open_Top"].length);
            col.gameObject.SetActive(true);
            col.gameObject.GetComponent<Animation>().enabled = true;
            animation["Close_Top"].speed = -5f;
            animation["Close_Top"].time = animation["Close_Top"].length;
            animation.Play("Close_Top");
            yield return new WaitForSeconds(capture_fail.length);
        }
        Destroy(gameObject);
        yield return null;
    }
}

据我了解,当你调用协程时,它会等待答案。但是你打电话给他们之后的部分会继续。所以它不会等待那个。答案只会在稍后给出。所以你只需要给你的第一个协程一个值,然后在你唤醒你的刚体之前检查这个值是否存在。

解决了...

    Vector3 move_to = new Vector3(transform.position.x-1.5f, col.contacts[0].point.y+1.5f, transform.position.z-1.5f);
    while(Vector3.Distance(transform.position, move_to) > 0.01f)
    {
        rigidbody.velocity = Vector3.zero;
        rigidbody.angularVelocity = Vector3.zero;
        rigidbody.Sleep();
        transform.LookAt(col.transform.position);
        transform.position = Vector3.Lerp(transform.position, move_to, 5f * Time.deltaTime);
        yield return null;
    }

这个 while 循环导致刚体在每次循环时醒来并进入睡眠状态。在最后一次迭代中,刚体仍然处于清醒状态,这导致球在应有的情况下掉落。将其更改为...

  rigidbody.velocity = Vector3.zero;
  rigidbody.angularVelocity = Vector3.zero;
  rigidbody.Sleep();
  Vector3 move_to = new Vector3(transform.position.x-1.5f, col.contacts[0].point.y+1.5f, transform.position.z-1.5f);
  while(Vector3.Distance(transform.position, move_to) > 0.01f)
  {
   transform.LookAt(col.transform.position);
   transform.position = Vector3.Lerp(transform.position, move_to, 5f * Time.deltaTime);
   yield return null;
  }

...而且它完美无缺。