Search code examples
c#unity-game-enginecoroutineyield-returnienumerator

Coroutine Won't Yield


I can't figure out for the life of me why this coroutine won't yield.

This section of code...

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;
        }

...won't yield. It just goes right through it. I know it does because during run-time, I play the game frame-by-frame, and I can watch this line of code...

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

...executing before the rotation finishes being adjusted. Any reason why this might be happening?

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;
    }
}

Solution

  • Solved it...

        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;
        }
    

    This while loop was causing the rigidbody to wake up and go to sleep everytime it looped. On its final iteration, the rigidbody was still awake, which caused the ball to drop before it should. Changed it to...

      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;
      }
    

    ...and it works flawlessly.