Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Rendering of a 2D Grid

Discussion in '2D' started by redapplesonly, Jun 11, 2023.

  1. redapplesonly

    redapplesonly

    Joined:
    Nov 8, 2021
    Posts:
    42
    I have a 2D strategy game that is played out on a grid of squares, like a superlarge chessboard. Each square is built from a GridSquare prefab, which will contain images, some text, things like that. The grid managed by a "GridManager" GameObject, and the C# script attached to that GO builds the grid like this:

    Code (CSharp):
    1.     void GenerateGrid()
    2.     {
    3.         for (int y = 0; y < cols; y++)
    4.         {
    5.             for (int x = 0; x < rows; x++)
    6.             {
    7.                 // Instanciate a grid square
    8.                 var spawnedGS = Instantiate(GridSquare, new Vector3(x, y), Quaternion.identity, parentObjectOfLittleSquares.transform);
    9.             }
    10.         }
    11.     }
    (FYI, in the Unity Editor, the GridSquare prefab has its own Sorting Layer, and every GridSquare is instantiated on Sorting Order 0 of that layer. So, all GridSquares should be instantiated at the same layer.)

    When the player moves their mouse over a GridSquare, I'd like that square to both enlarge and be rendered above all of other GridSquares. I used this code in the GridSquare's C# script:

    Code (CSharp):
    1.     void OnMouseEnter()
    2.     {
    3.         transform.localScale += Vector3.one * .25f;    // Enlarge the Square
    4.         // Cause this GridSquare to be rendered higher in the layer:
    5.         SortingGroup sortingGroup = GetComponent<SortingGroup>();
    6.         sortingGroup.sortingOrder += 10;
    7.     }
    8.  
    9.     void OnMouseExit()
    10.     {
    11.         transform.localScale -= Vector3.one* .25f;    // Shrink the Square
    12.         // Cause this GridSquare to be rendered higher in the layer:
    13.         SortingGroup sortingGroup = GetComponent<SortingGroup>();
    14.         sortingGroup.sortingOrder -= 10;
    15.     }
    The code does visually enlarge and shrink a GridSquare as I'd wanted. And when I watch the objects in the VisualStudios debugger, I can see that the GridSquare's sorting order is increased/decreased accordingly. But the "render this GridSquare above all others" part is not working.

    Here is what the game looks like before I hover the mouse:


    And here is me mouse-hovering over the planet Sualli:


    As you can see, the target GridSquare is enlarged, but not rendered above all other GridSquares. I'm not sure why, but I wondered if perhaps the for loop that I used to generate the Grid is to blame? The grid is instantiated one GridSquare at a time, working downward in columns. Is it possible that while my mouse is hovering over a GridSquare, Unity is rendering that GridSquare first, but then when it renders all the other Squares, the target square is, ah, painted over? Am I misunderstanding what is going on?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Are those things actually sprites? I see text... if they are UnityEngine.UI Image, they sort by a different mechanism.

    Either way, here's the layering / ordering skinny checklist:

    Three (3) primary ways that Unity draws / stacks / sorts / layers / overlays stuff:

    https://forum.unity.com/threads/orthographic-camera-rendering-order.1114078/#post-7167037

    In short, as far as the Standard Rendering Pipeline,

    1. The default 3D Renderers draw stuff according to Z depth - distance from camera.

    2. SpriteRenderers draw according to their Sorting Layer and Sorting Depth properties

    3. UI Canvas Renderers draw in linear transform sequence, like a stack of papers

    If you find that you need to mix and match items using these different ways of rendering, and have them appear in ways they are not initially designed for, you need to:

    - identify what you are using
    - search online for the combination of things you are doing and how to to achieve what you want.

    There may be more than one solution to try.

    For instance, you may even use multiple co-located cameras to more-explicitly control apparent draw ordering.

    Additional reading in the official docs:

    https://docs.unity3d.com/Manual/2DSorting.html

    And SortingGroups can also be extremely helpful in certain circumstances:

    https://docs.unity3d.com/Manual/class-SortingGroup.html

    Other rendering pipelines may have other ways of layering (HDRP and URP). Go see the latest docs for details.
     
    redapplesonly likes this.
  3. redapplesonly

    redapplesonly

    Joined:
    Nov 8, 2021
    Posts:
    42
    @Kurt-Dekker Thanks Kurt, Yeah, you're correct, my GridSquare prefab consists of a few 2D Sprites and one UI TextMeshPro object for the planets' nametag. (There's also some lines drawn around the border of the GridSquare.)

    Honestly, when the mouse hovers over a GridSquare, what I most want to happen is for that UI TextMeshPro object to be rendered above everything else. Probably because the Text object is a UI object, Unity renders it differently than all the other prefab components. (Why doesn't Unity support a non-UI Text object??? If only I could insert a 2D text field into the prefab that was treated like the Sprites...) Based on your advice, I see I have to start researching how to cause a UI TextMeshPro to appear over all other objects. Thanks again for your expert help, it goes a long way to educating noobs like me.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    It does! There's a lot of ways to get text onscreen.
    TextMesh
    is the original OG in-scene version while
    TextMeshPro
    is the new TMPro-based way.

    Neither of those works with a Canvas / CanvasRenderer. They are a "non-ui Text object" as far as I define it.

    For your game though I would just stay in UI space, unless perhaps you want 3D objects in those little boxes. If you want just 2D textures, just use all UI. Mixing and matching with no real need is only going to add headaches.

    You might even do something where a grid selection manager would copy a target grid cell while you have it selected, parenting this temporary copy to a completely different peer RectTransform so that it sorts above all the others, pulsing it, etc. Then when you deselect it, it destroys the copy, revealing the one underneath.
     
    redapplesonly likes this.
  5. karderos

    karderos

    Joined:
    Mar 28, 2023
    Posts:
    376
    you can use

    https://docs.unity3d.com/ScriptReference/Transform.SetSiblingIndex.html

    to change the ordering of the hierarchy and cause it to display above
     
    redapplesonly likes this.
  6. redapplesonly

    redapplesonly

    Joined:
    Nov 8, 2021
    Posts:
    42
    @Kurt-Dekker

    Hmmmm, that's an interesting suggestion. Because, yes, my GridSquare prefab GameObject has non-UI 2D Sprites glued together with that UI TextMeshPro nametag, and that construction already causing headaches galore. As rookie mistakes go, I guess it could have been worse.

    But if I may ask a follow-up question? Your idea of converting my entire gameboard into UI components has got the wheels in my head turning. From the tutorials I read, I got the impression that UI was strictly for, well, the user interface and shouldn't ever be used to build anything within the universe of your gamespace. Wouldn't building a UI gameboard violate that concept and make for bigger headaches later on? Thanks for taking the time to educate, I learn a lot from you.
     
  7. redapplesonly

    redapplesonly

    Joined:
    Nov 8, 2021
    Posts:
    42
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Attached is a grid-driven dynamic UI example: code procedurally makes buttons based on the sprites it finds. It's a pattern I use all the time to create arbitrary collections of stuff in either UI or anywhere really.

    The work has to be done for your game input, output, game logic, etc., regardless of how you present it.

    At the end of the day UI vs Sprite vs 3D objects is just different ways of organizing stuff that you want to be shoveled off to the graphics card and onto the screen in a timely fashion.
     

    Attached Files:

    redapplesonly likes this.
  9. redapplesonly

    redapplesonly

    Joined:
    Nov 8, 2021
    Posts:
    42
    @Kurt-Dekker This is great, thank you! Much appreciated...!
     
    Kurt-Dekker likes this.