HELP, infinite loop somewhere, can't find it

Hey, everything was working great, then I put in a couple new features on other scripts, and now everything is messed up. I don’t know why, but I think I must be getting an infinite loop somewhere on this script. My game is about boxes that you put in bins. You used to be able to drag the boxes around, but now when you touch them, the whole editor locks up and cannot be recovered. Here is my code, please forgive its spagettiness, I literally had no clue what I was doing when I started it:

using UnityEngine;
using System.Collections;

public class Touch : MonoBehaviour {
    bool paused = false;
    bool exists = true;
    bool wasThis = false;
    SpriteRenderer sr;
    public Sprite red;
    public Sprite blue;
    public Sprite green;
    public Sprite purple;
    public Sprite orange;
    GameObject rightBin;
    int color;
    /* public Vector2 binR;
    public Vector2 binB;
    public Vector2 binG;
    public Vector2 binP;
    public Vector2 binO; */
    Vector2 binPosition;
    public float toleranceX;
    public float toleranceY;
    bool selected; //box selected
    bool isThis;
    public bool followTrack = true; //for testing, can disable movement of box along track
    float trackX; //X position when following track
    float trackY; //Y position when following track
    public float speed = 0.1f; //Speed of box while following track (Should be same as track speed for best result)


  

    void Start () {
      
        GameObject go = transform.gameObject;
        sr = go.GetComponent<SpriteRenderer>();

        if (sr.sprite == red) {
            color = 1;
            GameObject.Find("barRed").SendMessage("findBox", transform.gameObject);
            GameObject.Find("barRed").SendMessage("getBin"); //must name exactly this in hirarchy!!!!!!
        } else if (sr.sprite == blue) {
            color = 2;
            GameObject.Find("barBlue").SendMessage("findBox", transform.gameObject);
            GameObject.Find("barBlue").SendMessage("getBin");  //must name exactly this in hirarchy!!!!!!
        } else if (sr.sprite == green) {
            color = 3;
            GameObject.Find("barGreen").SendMessage("findBox", transform.gameObject);
            GameObject.Find("barGreen").SendMessage("getBin");//must name exactly this in hirarchy!!!!!!
        } else if (sr.sprite == purple) {
            color = 4;
            GameObject.Find("barPurple").SendMessage("findBox", transform.gameObject);
            GameObject.Find("barPurple").SendMessage("getBin");  //must name exactly this in hirarchy!!!!!!
        } else if (sr.sprite == orange) {
            color = 5;
            GameObject.Find("barOrange").SendMessage("findBox", transform.gameObject);
            GameObject.Find("barOrange").SendMessage("getBin");  //must name exactly this in hirarchy!!!!!!
        }
        else { color = -1; }

       
        selected = false;
        isThis = false;
        if (followTrack)
        {
            trackX = -8.5f; //Sets start X position at -8.5
            trackY = Random.Range(-2.3f, -1.1f); //Sets starting Y position between -2.3 and -1
            transform.position = new Vector3(trackX, trackY, 1 - trackY);
        }
    }

    void acceptBin(GameObject bin)
    {
        rightBin = bin;
        binPosition = bin.transform.position;
        //print(gameObject + " " + binPosition);
    }
    void Update () {
        //test++;
        if (!paused)
        {
            RaycastHit hit;
            if (Input.touchCount > 0) //If there is a touch
            {

                Vector3 pos = Input.GetTouch(0).position; //Get its position
                //Debug.Log("Touch " + pos);

                Ray ray = Camera.main.ScreenPointToRay(pos); //check to see if it is colliding with the box
                if (Physics.Raycast(ray, out hit)) //if it is
                {

                    hit.transform.position = new Vector2(Camera.main.ScreenToWorldPoint(pos).x, Camera.main.ScreenToWorldPoint(pos).y); //Move box to that position
                    selected = true;
                    if (hit.transform == transform)
                    {
                        isThis = true;
                        wasThis = true;
                        if (overBin() && exists) { rightBin.SendMessage("boxOver", transform.gameObject); }

                    }
                    else { isThis = false; notThis(); }
                    //Debug.Log("Something hit " + Camera.main.ScreenToWorldPoint(pos));
                }
                else { selected = false; isThis = false; notThis(); }

            }
            else { selected = false; isThis = false; }
            if (!isThis) { selected = false; }
            if ((!selected) && (trackX < 8.5f) && followTrack) //if not selected, on the screen, and movement is enabled
            {
                trackX += speed; //Change X by speed
                transform.position = new Vector2(trackX, trackY); //move box along track
            }
            else if (trackX > 8.5f)
            {
                GameObject.Find("LifeBar").SendMessage("onLifeDown");
                Destroy(gameObject);
            }
            //Debug.Log(test + " " + selected);
        }
    }
    bool overBin()
    {
        print("overBin");
        if ((System.Math.Abs(transform.position.x - binPosition.x) <= toleranceX) && ((transform.position.y - binPosition.y) <= toleranceY))
        {
            return true;
        }
        else { return false; }
    }

    //methods to be called by other gameObjects

    void speedUp()
    {
        speed += .01f;
    }

    void speedDown()
    {
        speed -= .01f;
    }
    void checkColor(int col)
    {
        print("checkColor" + (wasThis));

        if ((col == color) && isThis)
        {
            exists = false;
            while (Input.touchCount < 0) { }
            GameObject.Find("LifeBar").SendMessage("onLifeUp");
            Destroy(gameObject);
        }
    }
    void notThis()
    {
        float time = Time.time;
        while (Time.time < time + 5.0f) { }
        wasThis = false;
    }
    void onPauseGame()
    {
        paused = true;
    }
    void onResumeGame()
    {
        paused = false;
    }
}

Thanks so much for looking over all of it. The messages are sent to the bins. If you think that might be where the problem is, I can post that code as well.

void notThis()
    {
        float time = Time.time;
        while (Time.time < time + 5.0f) { }
        wasThis = false;
    }

Because time = Time.time, Time.time is always < time + 5.0f
The empty loop goes on forever

I must admit I didn’t read the whole code, hoping there’s only that issue :slight_smile:

1 Like

There is also this gem waiting to bite

while (Input.touchCount < 0) { }

Although chances are it will never enter the loop, and so never lock up.

As a general rule you always need to make sure something inside the while loop must change the condition of the loop. Empty while loops will almost always form infinite loops.

1 Like

I don’t actually have any while loops, never trusted 'em.

2 Likes

I believe I read somewhere that NASA’s coding standards also don’t allow while loops. So you are in good company.

I on the other hand am a sucker for while (true) loops in coroutines.

3 Likes

@deathbydragon : Time.time (and Time.deltaTime) is set at the beginning of each frame (before Update), and won’t be updated before the end of the frame (before the next Update). Which is why, as @Krambolage pointed out, your while loop will go on forever.

The easiest (to understand) solution is to save the time at which you want to start the countdown, and check how long that’s since in Update.

@Kiwasi :
You’ve got different standards of coding when bugs have caused billions of dollars worth of hardware to explode in the sky, several times.

One of the most common mistakes new programmers in Unity makes is the while-time-is-less-than infinite loop. Because of the disconnected nature of MonoBehaviours, it would be completely intuitive to someone’s that new to this that they would run in parallel. A single MB locking the main thread doesn’t fit with the MB as independent component idea at all.

Yup. In my day job most critical systems have two independent code systems and a human watching them at all times.

My games are not so robust.

But who watches the watcher?

1 Like

… a board of international experts who can’t tell the difference between feet and meters? :eyes::roll_eyes::sunglasses:

That’s my job. :wink:

1 Like

Thanks so much guys, this has been very useful :slight_smile: