This seems to be a pretty simple problem that I haven’t been able to solve so I’ve come here for some help.
I’m trying to figure out why this if statement isn’t true and moving execution to the code it contains. As you can see in the attached picture below, there’s an else if and a else. Even though it says, in the local window, that tile.transform.rotation.eulerAngles.z is 180, its executing the else code instead of the else if.
The rotation for this object is set and doesn’t change, so it seems unlikely that its a float comparison problem.
I have no idea where to go with this. Any input would be greatly appreciated, thanks.
Use Mathf.Round and try with that as it is chance that angle is 180.0000000000001 or 179.999999999999,
maybe also if dont want round function you can cast it into int
I tried using Mathf.Round to round and casting the angle to a int with no success. The rotation for this object is set and doesn’t change, so it seems unlikely that its a float comparison problem.
On the note of floating comparison problems, there’s always Mathf.Approximately for this purpose to make it simpler. That way you can easily see if it changes anything or not with minimal effort.
Just setting floats at all is unreliable as stated above it can be 180.0000001 or 179.999999 this explains it. That said, I always check <= or >= for floats, too risky to try == but if you tried Mathf.Round… Doesn’t that also return a float? Anyways if its “set” what is setting it? A script? You might want to try Debug.Logging the euler angles. I know above it says 180 but better to be safe than sorry. You could also try checking the code above to see if anything is preventing from getting to the “else if” statement. And if it is a float comparison problem, another solution is Mathf.Approximately.
Well in my code i used round and it worked well but in comparison on one place i had to use 134<x && 136>x. so it all depends on how accurate you need. 179.6f<x && 180.4f>x are working use that if not look for more detailed option but i think comparing it like that should get you good results
The object is created using Instantiate and its rotation is set there. There’s no physics involved. I printed out the z angle and it was 180 to. The break point being reached is, I think, good evidence that the program is reaching the else if.
It doesn’t matter if there are physics involved or not. It also doesn’t matter if the Z was set to 180.0, since Unity stores rotations as quaternions, which involves conversion, and reading the euler angles doesn’t necessarily get back exactly what you put in. The fact of the matter is that you should never use exact float comparisons, especially not with eulerAngles.
So your suggesting not using eulearAngles at all because conversion could mess things up?
Here is the whole function that this bug is about.
private void GiveTilesAdjacentTiles(){
GameObject[] tileArray = GameObject.FindGameObjectsWithTag("Tile");
Debug.Log (tileArray.Length);
foreach (GameObject tile in tileArray){
TileInformation tInfo = tile.GetComponent<TileInformation>();
Vector3 tPos = tile.transform.position;
List<Vector3> adjecentPos = new List<Vector3>();
Debug.Log ("Tile",tile);
if (tInfo != null){
// Check left
if (tInfo.RowPos != 1){
adjecentPos.Add(new Vector3(tPos.x - tileWidth, tPos.y));
}
// Check right
if (tInfo.RowPos != tInfo.RowLength){
adjecentPos.Add(new Vector3(tPos.x + tileWidth, tPos.y));
}
Debug.Log ("rotation.z =" + tile.transform.rotation.eulerAngles.z, tile);
// Check up and down
if (tile.transform.rotation.eulerAngles.z >= -1f && tile.transform.rotation.eulerAngles.z <= 1f){ // check down
// Have to check this here in order not to mess up the rotatoin check
Debug.Log ("tile.transform.rotation.eulerAngles.z == 0 ");
if (tInfo.Row != 1){
adjecentPos.Add (new Vector3(tPos.x, tPos.y - tileHeight));
}
}
else if (tile.transform.rotation.eulerAngles.z >= 179f && tile.transform.rotation.eulerAngles.z <= 181f){ // check up
// Have to check this here in order not to mess up the rotatoin check
Debug.Log ("tile.transform.rotation.eulerAngles.z == 180 ");
if (tInfo.Row != tInfo.RowCount){
adjecentPos.Add (new Vector3(tPos.x, tPos.y + tileHeight));
}
}
else { // If the tile doesnt have a rotation of 180 or 0 then there's a problem
Debug.LogError("Tile doesnt have a z rotation of 0 or 180");
}
// Search through the array of tiles for the tiles that match the expected pos's
foreach (Vector3 p in adjecentPos){
foreach (GameObject t in tileArray){
if (t.transform.position.x == p.x & t.transform.position.y == p.y){
tInfo.AdjecentTiles.Add (t); // Add this tile to the list of adjecnt tiles
break; // Break out of the loop becuase its found the tile it was looking for
}
}
}
}
}
Here’s the function that creates the objects used in the above function. Not directly about the bug but thought ya might want it.
// Creates a hexagon board, centered at (0,0) made out of tile triangles
public void GenerateBoard(int layers){
// Rows will always be even
int rows = layers * 2;
int smallestRow = (layers-1) * 2 + 3;
int largestRow = (layers-1) * 4 + 3;
for (int i = 1; i <= rows;i++){
float oddRotation;
float evenRotation;
// Calculate the length of this row
int rowLength;
if (i > rows/2){
rowLength = largestRow - (((i - rows/2) - 1)* 2);
oddRotation = 0f;
evenRotation = 180f;
}
else {
rowLength = smallestRow + ((i - 1) * 2);
oddRotation = 180f;
evenRotation = 0f;
}
// Gets the y pos for this row
float y = (-tileHeight * (rows/2)) + tileHeight * (i-1) + tileHeight/2;
// Create the row
for (int k = 1; k <= rowLength; k++){
// Calculate the x pos for this tile
float x = (-tileWidth * (rowLength/2)) + tileWidth * (k-1) + tileWidth/2;
Vector3 pos = new Vector3(x,y,0f);
Quaternion rotation = new Quaternion();
// If the tile number in the row is even
if (((float)k)/2 == Mathf.Floor(((float)k)/2)){
rotation.eulerAngles = new Vector3(0f,0f,evenRotation);
}
// If its odd
else{
rotation.eulerAngles = new Vector3(0f,0f,oddRotation);
}
GameObject t = Instantiate(tile, pos, rotation) as GameObject;
TileInformation tileInfo = t.GetComponent<TileInformation>();
tileInfo.RowPos = k;
tileInfo.Row = i;
tileInfo.RowLength = rowLength;
tileInfo.RowCount = rows;
// Cant give tiles their adjacent tiles here because the whole board isnt created yet
}
}
GiveTilesAdjacentTiles();
}
I’m suggesting not comparing directly to 180.0 using ==, but it’s also true that the rotation might not be anywhere near that. e.g., rotations of (0, 0, 0) and (180, 180, 180) are the same. So reading a single axis can be prone to failure, since it’s out of context. It’s possible that the Z could be 180 (or close to it) one frame, and then 0 the next, and both would be correct.
so this < && > dont work? try putting || to check or (maybe is some time/space anomaly).
i mean if it debugs z = 180.0 it should work between 179 and 181
might want to try just
Debug.Log ( tile.transform.rotation.eulerAngles.z);
before if statments because i see you have , tile even tho i dont know why exactly.
trial and error
The rotation of the object is set in one of two possible states when its created and is never changed throughout the duration of it’s life. Which makes me think of just storing it’s rotation state as a bool in the object and using that instead of messing with float comparison. Also, the code that this is referring to is ran on Start.
I’ve looked at the tile.transform.rotation.eulerAngles.z both through Debug.Log and the Mono-Develop debugger and am fairly certain that it is 180 when it reaches the else if.
Really have no idea, (probably something really stupid as always) but <> worked for me.
If can use booleans and you are good to go, less worries the better
Regarding the posted code, if the Debug from this is firing:
// Check up and down
if (tile.transform.rotation.eulerAngles.z >= -1f && tile.transform.rotation.eulerAngles.z <= 1f){ // check down
// Have to check this here in order not to mess up the rotatoin check
Debug.Log ("tile.transform.rotation.eulerAngles.z == 0 ");
if (tInfo.Row != 1){
adjecentPos.Add (new Vector3(tPos.x, tPos.y - tileHeight));
}
}
Then you know that it’s not getting to that “else if” statement. But what you stated above, it seems to be 180… Key word “Seems”. I still think you should try Mathf.Approximately, but a more surefire way as you said would be to use bools. However save yourself some frustration and just make an integer value in your TileInformation script.
int instantiatedRotation;
And set that to be EXACTLY 0 (This works because it’s an integer) or EXACTLY 180 when you generate the tile. So when you do Instantiate(tile, pos, rotation); just set the variable based off the evenRotation calculations you have in the generator script.
Is there a chance that whatever testing you are using tInfo.Row == tInfo.RowCount? That being said you need to put debug statements everywhere, and let us know what is firing, and what isn’t. For example when you run the test are you receiving your debug.logerror(Tile doesnt have a z rotation of 0 or 180") demonstrating that no if statements fired. Or are you actually getting “tile.transform.rotation.eulerAngles.z == 180” from line 33?
Another option to consider is on my part not fully knowing Unity. But I would imagine that your first if statement for the angles. All Rotations would technically be tile.transform.rotation.eulerAngles.z >= -1f && tile.transform.rotation.eulerAngles.z <= 1f
Right? Since it’s cyclical once you hit 360, you just go back to 0? I don’t know just my 3 cents
Edit: I tested the idea that it is cyclical, it is not. I’d like to know exactly which debug statements are running.