- Home /
Is having a "break" in a "foreach" loop that is itself inside a "for" loop breaking both loops?
Hi dear members,
Is having a "break" in a "foreach" loop -that is itself inside a "for" loop- breaking both loops (foreach is the direct one where the "break" command is called, but foreach is itself nested in a for loop) or only the direct one (foreach)?
I get no errors, but the behavior is not EXACTLY how I intend it to be, so I am wondering if the problem can originate from how the break command behaves... I want to stop the foreach loop on break, however the for loop should go on until g<4.
Part of my code I wonder about:
for (g=1;g<4;g++)
{
if (g == 1)
{
gos = GameObject.FindGameObjectsWithTag("crabtag");
}
else if (g == 2) {
gos = GameObject.FindGameObjectsWithTag("turtletag");
}
else if (g == 3)
{
gos = GameObject.FindGameObjectsWithTag("jellytag");
}
foreach(GameObject go in gos)
{
if (playerposx == go.transform.position.x && playerposy == go.transform.position.y)
{
if (g == 1)
{
crabHere = true;
break;
}
else if (g == 2)
{
turtleHere = true;
break;
}
else if (g == 3)
{
jellyHere = true;
break;
}
}
else
{
if (g == 1)
{
crabHere = false;
}
else if (g == 2)
{
turtleHere = false;
}
else if (g == 3)
{
jellyHere = false;
}
}
}
}
I reindented your code. Next time try to use the code formatting option (button "010101").
Is this line
if (playerposx == go.transform.position.x && playerposy == go.transform.position.y)
getting any success? You are comparing float numbers. Those are really unlikely to be exactly the same. You might want to clamp the value within a range to optimize your chance of success.
@Fattie Well yes. That's part of my answer already, isn't it? =D
fafase ... re your critical comment. they could also use "$$anonymous$$athf.approximately" (or should at least know about it).
Oh yes, there are various ways to achieve that, a couple of if statements would do it and avoid the tiny overhead of a function for instance.But I was just mentioning quickly that there could be something wrong there.
Answer by Demigiant · Oct 17, 2012 at 01:25 PM
Just to post a clear answer to the question: no ;)
Breaking within a loop will break only the exact loop you're in, without considering its parents.
That's what it's come to huh - now even Javascript Break isn't considering it's parents. What is the world co$$anonymous$$g to ;)
BTW it's a disturbing point that I actually DID NOT $$anonymous$$NOW the answer to this in the U/S/U3D milieu.
Is it in fact true wot $$anonymous$$e said?
(this is exactly the sort of reason one should never use control structures like this :O for me it all went wrong when we left the oceans and "if" with "go to" :O )
@Fattie I use some nested loops in the tween engine I made for Unity (HOTween), and I can confirm that break behaves as usual ;) (and I also have to admit I once used a goto, to fully break out of a nested loop - shame on me! :D) (P.S. I have no idea why my answers are nicknamed "$$anonymous$$e" and my comments "Izitmee" :P)
Answer by echofiend · Oct 17, 2012 at 06:59 AM
As Mike states, the code is hard to read in its current formatting and appears to be linked. As a helpful hint to the future, try to keep only one entry and one exit to every loop/method, multiple breaks and continues can render code hard to debug.
Answer by Kryptos · Oct 17, 2012 at 07:45 AM
To answer your question: No, there is nothing wrong with the break
statement.
But your code logic looks a bit weird. Try to make a dedicated method instead of series of if... else
. Something like:
public enum Animal { Crab, Turtle, Jelly }
// ...
void MainMethod(Vector3 playerPosition)
{
crabHere = CheckAnimal(Animal.Crab, playerPosition);
turtleHere = CheckAnimal(Animal.Turtle, playerPosition);
jellyHere = CheckAnimal(Animal.Jelly, playerPosition);
}
bool CheckAnimal(Animal animal, Vector3 playerPosition)
{
GameObject[] gos = null;
switch (animal)
{
default:
return false;
case Crab:
gos = GameObject.FindGameObjectsWithTag("crabtag");
break;
case Turtle:
gos = GameObject.FindGameObjectsWithTag("turtletag");
break;
case Jelly:
gos = GameObject.FindGameObjectsWithTag("jellytag");
break;
}
if (!gos || gos.Length == 0)
{
return false;
}
foreach(GameObject go in gos)
{
if (playerPosition.x == go.transform.position.x && playerPosition.y == go.transform.position.y)
{
return true;
}
}
return false;
}
The main problems with your code were:
Hard to read.
Hard to debug.
Float comparison as @fafase pointed out. You should consider using Mathf.Approximately or use Vector.sqrMagnitude:
if (playerPosition - go.transform.position).sqrMagnitude < 1.0f
Thanks to everybody who answered. Sorry for the bad indent, it was looking fine when I previewed my post. The answer to my question was no, it breaks only the loop in where the break is nested. Comparing float values is not a problem for my game development, this is a 2.5D game and it works like a charm comparing them.
One thing though, is there any PERFOR$$anonymous$$ANCE advantage in using Nicolas' way (enumerator) versus $$anonymous$$e?
I never tested it directly, but actually comparing an int value VS comparing an Enum value should be slightly faster (though way less readable). What he said about float comparisons ins$$anonymous$$d is completely true. When comparing a float, you should always use approximations as he mentioned, otherwise you could have wrong results, sometimes.
Not at all. Enum/switch are faster because the compiler can optimize the flow control.
Sorry, I was thinking about the comparison only: a switch that checks an int value (passed directly as a value, meaning "myInt == 1" and not "myInt == anotherInt") VS a switch that checks an enum value should in theory be slightly faster?
An enum is stored as an integer in any case. @$$anonymous$$ryptos means that as there are only a limited set of candidate values it is possible for the compiler to predict what values the int can contain, a real int could contain 4bn values, an enum is likely to have a lot fewer values - either that or someone did a lot of typing :)