C# while loop question

Hi to all,

I'm converting scripts from Javascript to C#... well because I prefer that but lately, I've been running into an issue with the while loop. where it always hangs Unity Editor or my game if used inside the Update function. (It's weirs because they all work in javascript with the while loop!?!?)

In some instances, I got ride of the while loop and I managed to get the scrip to work but in other cases, The script will not work properly.

In the dragrigidbody script, for exemple, If I remove the while loop, it will not drag the gameobject that I select.

Here's part of the code (script taken from shadow project :-) ) so for those you are more visual can get a look at it;

`

using UnityEngine;
using System.Collections;

public class DragRigidbody : MonoBehaviour 
{

    #region Variables

    public float spring = 50.0f;
    public float damper = 5.0f;
    public float drag = 10.0f;
    public float angularDrag = 5.0f;
    public float distance = 0.2f;  
    public float pushForce = 0.2f;
    public bool attachToCenterOfMass = false;
    public Material highlightMaterial;

    private GameObject highlightObject;
    private SpringJoint springJoint;

    #endregion

    void Update()
    {
        Camera mainCamera = FindCamera();

        highlightObject = null;

        // We need to actually hit an object
        RaycastHit hit_01;
        if(Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition), out hit_01, 100.0f))
        {
            if(hit_01.rigidbody && !hit_01.rigidbody.isKinematic)
            {
                highlightObject = hit_01.rigidbody.gameObject;
            }
        }

        // Make sure the user pressed the mouse down
        if(!Input.GetMouseButtonDown(0))
            return;

        // We need to actually hit an object
        RaycastHit hit;
        if(!Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition), out hit, 100.0f))
        {
            return;
        }
        // We need to hit a rigidbody that is not kinematic
        if(!hit.rigidbody || hit.rigidbody.isKinematic)
        {
            return;
        }

        if(!springJoint)
        {
            GameObject go = new GameObject("Rigidbody dragger");
            go.AddComponent("Rigidbody");
            springJoint = (SpringJoint)go.AddComponent("SpringJoint");
            go.rigidbody.isKinematic = true;
        }

        springJoint.transform.position = hit.point;
        if(attachToCenterOfMass)
        {
            Vector3 anchor = transform.TransformDirection(hit.rigidbody.centerOfMass) + hit.rigidbody.transform.position;
            anchor = springJoint.transform.InverseTransformPoint(anchor);
            springJoint.anchor = anchor;
        }
        else
        {
            springJoint.anchor = Vector3.zero;
        }

        springJoint.spring = spring;
        springJoint.damper = damper;
        springJoint.maxDistance = distance;
        springJoint.connectedBody = hit.rigidbody;

        DragObject(hit.distance, hit.point, mainCamera.ScreenPointToRay(Input.mousePosition).direction);
    }

    void DragObject(float distance, Vector3 hitpoint, Vector3 dir)
    {
        float startTime = Time.time;
        Vector3 mousePos = Input.mousePosition;

        float oldDrag = springJoint.connectedBody.drag;
        float oldAngularDrag = springJoint.connectedBody.angularDrag;
        springJoint.connectedBody.drag = drag;
        springJoint.connectedBody.angularDrag = angularDrag;
        Camera mainCamera = FindCamera();

        while(Input.GetMouseButton(0))  // <-- freezes here even if my StartCoroutine is uncommented or commented
        {
            Ray ray = mainCamera.ScreenPointToRay (Input.mousePosition);
            springJoint.transform.position = ray.GetPoint(distance);
            StartCoroutine(CoroutineYield());
        }

        if(Mathf.Abs(mousePos.x - Input.mousePosition.x) <= 2.0f && Mathf.Abs(mousePos.y - Input.mousePosition.y) <= 2.0f && Time.time - startTime < 0.2f && springJoint.connectedBody)
        {
            dir.y = 0.0f;
            dir.Normalize();
            springJoint.connectedBody.AddForceAtPosition(dir * pushForce, hitpoint, ForceMode.VelocityChange);
            ToggleLight( springJoint.connectedBody.gameObject );
        }

        if(springJoint.connectedBody)
        {
            springJoint.connectedBody.drag = oldDrag;
            springJoint.connectedBody.angularDrag = oldAngularDrag;
            springJoint.connectedBody = null;
        }
    }

    static void ToggleLight(GameObject go)
    {
        Light theLight = (Light)go.GetComponentInChildren(typeof(Light));
        if(!theLight)
        {
            return;
        }

        theLight.enabled = !theLight.enabled;
        bool illumOn = theLight.enabled;
        Component[] renderers = go.GetComponentsInChildren(typeof(MeshRenderer));
        foreach(MeshRenderer r in renderers)
        {
            if(r.gameObject.layer == 1)
            {
                r.material.shader = Shader.Find(illumOn ? "Self-Illumin/Diffuse" : "Diffuse");
            }
        }
    }

    Camera FindCamera()
    {
        if (camera)
            return camera;
        else
            return Camera.main;
    }

    void OnPostRender()
    {
        if(highlightObject == null)
            return;

        GameObject go = highlightObject;
        highlightMaterial.SetPass(0);
        Component[] meshes = go.GetComponentsInChildren(typeof(MeshFilter));
        foreach(MeshFilter m in meshes)
        {
            Graphics.DrawMeshNow(m.sharedMesh, m.transform.position, m.transform.rotation);
        }
    }

    IEnumerator CoroutineYield()
    {
        // Wait for one frame
        yield return 0;

        //// Wait for two seconds
        //yield return new WaitForSeconds(0.5f);
    }

}

`

So my question would be, how can I make it work? How can I use a while loop when I absolutely need one and getting it updated every frame or so without the editor or game freezing?

You would need to make your DragObject function itself a coroutine.

So it would look like this:

IEnumerator DragObject( stuff )
{
   // setup stuff
   while( Input.GetMouseButton( 0 ) )
   {
      // update position stuff
      yield return null; // returning null is faster than returning 0
   }
   //done with dragging stuff
}

Of course that's probably not going to be enough to actually get your script to work without putting pretty much everything after the `if( !Input.GetMouseButtonDown( 0 ) )` in your Update inside the coroutine itself as well. If that's the case, to "return" out of a coroutine you use `yield break;`

Hi maparizeau,
Can you please explain how you got the above script working.?
Thanks in advanceā€¦