Search Unity

[Bug] Tiles not flipping properly

Discussion in '2D' started by chatrat12, Sep 14, 2018.

  1. chatrat12

    chatrat12

    Joined:
    Jan 21, 2015
    Posts:
    122
    My experience with flipping and rotating tiles in Unity have been less than stellar. Some tiles refuse to flip and rotating does not always work in the scene view. Rotating seems to be more consistent when editing in the palette.

    Just to clarify, I'm using the keyboard shortcuts to rotate and flip. I noticed these shortcuts are not in the hotkey documentation. By default, you use the bracket keys to rotate and Shift + bracket keys to flip. They can be changed through Editor->Preferences->Keys.

    When I flip this selection of tiles, some flip and others will not.
    You can see there are issues on both the vertical and horizontal flip.
    TileFlipBug_0.gif

    This behavior is also interesting, I'm tying to flip these tiles vertically and you can see the selection outline updating but the tiles don't budge.
    TileFlipBug_1.gif

    I'm attaching a project with a tile palette so the bug can be reproduced.

    System
    Unity 2018.2.8f1
    Window 10

    Reproduction steps
    • Open the existing tile palette
    • Put the palette into edit mode
    • Use the picker to select a group of tiles (there are 2 groups in the palette provided)
    • Try flipping the selected tiles (Shift + left or right bracket)
    • Observer how it does not work properly
     

    Attached Files:

  2. chatrat12

    chatrat12

    Joined:
    Jan 21, 2015
    Posts:
    122
    So I dug through the C# reference. I think I figured out the issue... probably. Take a look at the
    FlipY
    method from
    GridBrush.cs
    .

    Code (CSharp):
    1. private void FlipY()
    2. {
    3.     BrushCell[] oldCells = m_Cells.Clone() as BrushCell[];
    4.     BoundsInt oldBounds = new BoundsInt(Vector3Int.zero, m_Size);
    5.  
    6.     foreach (Vector3Int oldPos in oldBounds.allPositionsWithin)
    7.     {
    8.         int newY = m_Size.y - oldPos.y - 1;
    9.         int toIndex = GetCellIndex(oldPos.x, newY, oldPos.z);
    10.         int fromIndex = GetCellIndex(oldPos);
    11.         m_Cells[toIndex] = oldCells[fromIndex];
    12.     }
    13.  
    14.     int newPivotY = m_Size.y - pivot.y - 1;
    15.     pivot = new Vector3Int(pivot.x, newPivotY, pivot.z);
    16.     Matrix4x4 flip = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, -1f, 1f));
    17.     foreach (BrushCell cell in m_Cells)
    18.     {
    19.         Matrix4x4 oldMatrix = cell.matrix;
    20.         cell.matrix = oldMatrix * flip;
    21.     }
    22. }
    The important bit is at the bottom.
    cell.matrix = oldMatrix * flip;
    I believe the matrix multiplication order is incorrect. It should read
    cell.matrix = flip * oldMatrix;
    .

    I had a new hunch to go on. So if I have a tile that has not been rotated at all (still has identity matrix), flipping works as intended. If I rotate the tile 90 degrees and then try to flip vertically, no visual result. If I then rotate the tile back 90, the tile has been flipped so the matrix is in fact being manipulated when I try to flip and it appears nothing is happening. I'm not sure why there is no visual result, even with incorrect multiplication order.

    So in my test, I am guessing the tiles that are failing to flip have been rotated.

    Wish I could test the fix, but we only have access to reference. If I have time later, I'll patch the editor assembly to see if my theory is correct.
     
  3. chatrat12

    chatrat12

    Joined:
    Jan 21, 2015
    Posts:
    122
    I patched the assembly and flipping is still broken, no visual result when I try to flip at certain orientations. I still believe that the matrix multiplication is wrong. I did a test on a tilemap to confirm.

    Code (CSharp):
    1. var bounds = tilemap.cellBounds;
    2. Matrix4x4 flip = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, -1f, 1f));
    3.  
    4. for (int y = bounds.yMin; y < bounds.yMax; y++)
    5. {
    6.     for (int x = bounds.xMin; x < bounds.xMax; x++)
    7.     {
    8.         var cell = new Vector3Int(x, y, 0);
    9.         if (tilemap.GetTile(cell) != null)
    10.         {
    11.             var oldMatrix = tilemap.GetTransformMatrix(cell);
    12.             // Does not work properly on rotated tiles.
    13.             // tilemap.SetTransformMatrix(cell, oldMatrix * flip);
    14.             // Works on rotated tiles
    15.             tilemap.SetTransformMatrix(cell, flip * oldMatrix);
    16.                        
    17.         }
    18.     }
    19. }
    Wish we had access to source so I could dig deeper :\
     
  4. chatrat12

    chatrat12

    Joined:
    Jan 21, 2015
    Posts:
    122
    My patch where I changed the matrix multiplication order actually did fix the issues in my first example, however the second example still does not work.

    TileFlipBug_0_Fixed.gif
     
  5. chatrat12

    chatrat12

    Joined:
    Jan 21, 2015
    Posts:
    122
    I found some more interesting behavior. For the second group of tiles that are still not flipping properly after I patched my editor assembly, they flip properly if my selection dimensions are larger than 2 for the axis I am try to flip. This whole thing is a little perplexing.
    TileFlipBug_1_Workaround.gif
    Whether the dimension is even or odd does not seem to matter. As long as its larger than 2. That being said, doing 2x2 selections on the first group of tiles WILL flip properly :\