- Home /
C#, code stops loop prematurely
I have a selector class to select game objects (and parent a guiTexture to them to show they are selected) for an rts game im making. When i have my deselectAll method run, it loops through the arrayList of all the selected game objects and selects them one by one, then sets a global variable to false, saying nothing is selected. When i execute this method, and have two objects selected, it stops before the last one to be deselected and just stops. My loops is set up to run the correct amount of times, and the game objects are added to the arrayList correctly.
Here are 4 images, showing my selection i make and then when i try to deselect my units.
Here is my code for deselecting all objects, and my deselect object method:
public void deselectAll()
{
debugGText.permDebugNoNL("selObjList count = " + selObjList.Count + " deselectAll loop: ");
for(int i = 0;i<selObjList.Count;i++)
{
debugGText.permDebugNoNL(" i= " + i);
//debugGText.permDebugNoNL(" " + i + "and obj in deselect loop is: " + selObjList[i].transform.parent.gameObject.name);
if(selObjList[i].transform.parent.gameObject == null)
{
debugGText.permDebug("selObjList[i].transform.parent.gameObject is null");
}
debugGText.permDebug("calling deselect");
deselectObj( selObjList[i].transform.parent.gameObject);
}
debugGText.permDebug(" setting somethingSelected to false, and selObjList size: " + selObjList.Count);
somethingSelected = false;
}
Here is my code for my deselect method:
public void deselectObj(GameObject g) //idx references when it was added, index would change
{
debugGText.permDebug("deselectObj method and obj is: " + g.name + " and size of ObjList: " + selObjList.Count);
GameObject hull = g.transform.Find("ShipHull").gameObject;
if(hull == null)
{
debugGText.permDebug("Hull to deselect is null");
}
ShipVars shipVars = hull.gameObject.GetComponent("ShipVars") as ShipVars; //fetch ShipVars object to check values
if(shipVars == null)
{
debugGText.permDebug("[deselectObj method] shipVars is null for this ob");
}
if(shipVars.isSelected == false)
{
debugGText.permDebug("[obj to deselect] isSelected = false");
}
//check this code to see if i can structure obj selection / removal from list.... (consider hash table or etc for index?)
if(selObjList.Contains(hull) )
{
if(hull.transform.Find("SelectedIndicatorGui(Clone)") != null)
{
debugGText.permDebug(" found selected obj on hull, deselecting...");
Destroy(hull.transform.Find("SelectedIndicatorGui(Clone)").gameObject); //instead try looping through all selectGui objs and then delete each one (we want to delete them all in this case) (In later cases we can use raycast or a smaller loop, for selection boxes, to destroy selectionGui objs)
selObjList.RemoveAt(selObjList.IndexOf(hull));
shipVars.isSelected = false; //set the current iterated ship variable to false
}
else
{
debugGText.permDebug("selectedGui not found on obj");
}
}
else
{
debugGText.permDebugNoNL("[in deselectObj method] selObjList doesnt contain hull");
}
debugGText.permDebug(" done with deselect method ");
}
}
My code for my deselect method runs fine for all objects except a few, which makes no sense. I checked and the objects arent null and are in the arrayList. My code doesnt even enter the deselect method, like the loop stops too short. I have my condition as: for(int i = 0;i
Which should iterate through all objects. If i remove my obj deselect call, it loops through all objects fine, so something in this deselectObj method is causing problems. What could it be?
Answer by Drakestar · May 06, 2012 at 06:36 AM
You're operating on an array that you're iterating over, which is always bad news. When you do this in deselectObj():
selObjList.RemoveAt(selObjList.IndexOf(hull));
and return to the first function, you have changed (decremented) the indices of all elements in the selObjListarray, without decrementing the counter i (and selObjList.Count changes for each loop). You're effectively skipping elements in the array which are never considered for removal. Easy test:
private List<int> iTest = new List<int>();
iTest.Add(0);
iTest.Add(1);
iTest.Add(2);
iTest.Add(3);
iTest.Add(4);
runiTest();
private void runiTest()
{
int iterationCount = 0;
for (int i = 0; i < iTest.Count; i++)
{
iTest.RemoveAt(i);
iterationCount++;
}
}
At the end, the iTest array still contains (1,3), and iterationCount is 3. Probably not what you wanted.
genius. How could i miss that? damn! ill give this a go and see if this fixes my problem.
I found a work around, your answer was correct by the way. Im so glad you pointed that out. Has been plaguing me for days....
I used: while(selObjList.Count > 0) { //deselect the first element in the list }
Usually it's enough to iterate backwards ;) In most situations where i need to remove elements i do it this way.
for (int i = iTest.Count-1; i>=0; i--)
Watch out, the limits need to be changed.