- Home /
How do I fix this loop causing the program to freeze?
I've been attempting to create a system that selects a random string from one of several array lists based on which lists I currently have set to be available, but have run into several issues.
The way it's meant to work is that my code selects a random number from a range, based on how many lists I have, then, through a series of if statements, tracks down the relevant list and determines whether or not its set to be available. If it is, the code selects a random string from that array and prints it to a text box in my scene. If it isn't, the code cycles through the remaining ifs, before looping back to the beginning through a while loop (formerly a for loop, but i've been trying different options whilst attempting to fix this), where the code "rerolls" the random number and tries again until a match happens, at which point the loop is broken until the function containing all of this is called again.
I'm running into a problem, though. Previously, before I implemented the loop (which was part of an overhaul to make my code more efficient and hundreds of lines shorter), the string call level was working fine, as was the selection of which lists were available (there were a few glitches, but I think I fixed them). Now, I can't even get to the string level because Unity freezes the moment I press the in-scene button that triggers the entire selection sequence.
Through research, i've learned this is probably being caused by the loop repeating forever without an exit point, but the way i've set it up, at least to me, seems like there should be one, as its meant to repeat until the number it generates matches one of the selected lists.
I'm out of ideas, basically, and am hoping that a fresh perspective will be able to see something obvious that my tired brain is skimming over.
public bool checkList1;
public bool checkList2;
public bool checkList3;
public bool checkList4;
public bool checkList5;
public bool checkList6;
public int findArray;
public int i;
public string resultText;
public Text resultOutput;
/*List1*/ public List<string> rand1 = new List<string>();
/*List2*/ public List<string> rand2 = new List<string>();
/*List3*/ public List<string> rand3 = new List<string>();
/*List4*/ public List<string> rand4 = new List<string>();
/*List5*/ public List<string> rand8 = new List<string>();
/*List6*/ public List<string> rand16 = new List<string>();
public void Start () {
checkList1 = false;
checkList2 = false;
checkList3 = false;
checkList4 = false;
checkList5 = false;
checkList6 = false;
findArray = -1;
i = 0;
resultText = "";
nameButton.onClick.AddListener (TaskOnClick);
}
public void Update () {
if (togList1.isOn) {
checkList1 = true;
}else{
checkList1 = false;
}
if (togList2.isOn) {
checkList2 = true;
}else{
checkList2 = false;
}
if (togList3.isOn)
{
checkList3 = true;
}else{
checkList3 = false;
}
if (togList4.isOn) {
checkList4 = true;
}else{
checkList4 = false;
}
if (togList5.isOn) {
checkList5 = true;
}else{
checkList5 = false;
}
if (togList5.isOn) {
checkList5 = true;
}else{
checkList5 = false;
}
}
public void TaskOnClick()
{
while (i == 0)
{
findArray = Random.Range(1, 17);
Debug.Log(findArray);
if (findArray == 1 && checkList1 == true)
{
Debug.Log("1");
i++;
CallRand1();
}
else if (findArray == 2 && checkList2 == true)
{
Debug.Log("2");
i++;
CallRand2();
}
else if (findArray == 3 && checkList3 == true)
{
Debug.Log("3");
i++;
CallRand3();
}
else if (findArray == 4 && checkList4 == true)
{
Debug.Log("4");
i++;
CallRand4();
}
else if (findArray == 8 && checkList5 == true)
{
Debug.Log("8");
i++;
CallRand8();
}
else if (findArray == 16 && checkList6 == true)
{
Debug.Log("16");
i++;
CallRand16();
}
else if (findArray >= 5 && findArray <= 7)
{
Debug.Log("UNUSED");
}
else if (findArray >= 9 && findArray <= 15)
{
Debug.Log("UNUSED");
}
}
}
Answer by Hellium · Oct 22, 2020 at 10:57 PM
How have you ended up with such script? Below is a suggestion of simplification, but you might not be able to apply to your code since you haven't provided your full script and you did not explain what it was supposed to do (except selecting random things)
[System.Serializable]
public class MyClass // Rename this class
{
public List<string> Rand = new List<string>();
public Toggle Toggle;
public string Foo()
{
// Do the logic of your CallRandX method
}
}
public class YourClassName : MonoBehaviour
{
public string resultText;
public Text resultOutput;
[SerializeField]
private MyClass[] MyClasses;
private void Start ()
{
resultText = "";
nameButton.onClick.AddListener(TaskOnClick);
}
public void TaskOnClick()
{
MyClass[] enabledClasses = System.Find( MyClasses, obj => obj.Toggle.isOn);
if(enabledClasses.Length == 0)
return;
int index = Random.Range(0, enabledClasses.Length);
resultText = enabledClasses[index].Foo();
resultOutput.text = resultText;
}
}
I didn't post the full script, this is true. The actual sections for random selection of strings aren't shown because I didn't view them as necessary to understanding the problem I was running into. That said, if you think they are, I can edit to show the missing sections as well.
And I appreciate the suggested simplification. It uses code i'm either unfamiliar with or haven't used in long enough to have forgotten them (if I had a simpler way of doing it myself, i'd already have done it), but i'll get my head around them and let you know if they work (although it could be problematic, given each CallRandX refers explicitly to a separate array list for its strings).
Answer by Miyed · Oct 23, 2020 at 07:09 AM
In your update, if TogListX.isOn is false, (i dont see it being set to true anywhere), it will set checkListX =false always. never to true.
If that's the case, then in your TaskOnClick(), checklistX will never be true, so even if you do get a good findArray number (4 for example), checklist4 will be false, so you wont enter into the if statement, therefore i++ is never called, meaning i is still 0, so your while(i==0) becomes an infinite loop.
The TogListXs are in-scene check-boxes. Sorry, I should have made that clearer, in hindsight. They're assigned to the iteration of the script rolled out in-scene and should be detectable as checked or not when its actually running.
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Random movement script not working C# 2 Answers
Random message generator out of control 1 Answer
Making a camera list 1 Answer