Conflict between component prefabs and Unity UI serialization bug

First off I love the component library concept.

So I was a little surprised no one else brought this up but how do you manage the conflict between creating lots of prefab overrides (as Sam shows) and the need to constantly “revert all” to undo problems from the UI serialization bug. I risk accidentally reverting something I wanted to keep.

So far I found that the best way to minimize overrides is to use lots of autolayout but it only gets you so far. For example I found no good way of dealing with an override on the scrollview. For example to get a nice big empty scroll view like the below you need an override. (see below)

Another very different option - it seems like you get a lot of overrides because you’re creating a prefab variant of a panel. How about starting with an empty game object instead and putting the panel as a child and then everything as a child. Then you prefab that parent as a new original prefab. The only catch I found is the parent is a rect instead of a rect transform and I don’t know if that will cause problems down the line.


Sam’s work below showing the large open scroll view

With a lot of pulling of hair, screaming, and hammering on the keyboard in frustration.
Also, by keeping autosave OFF (a habit I picked up long before this course).

It doesn’t. The important thing is the Canvas under the transform, which switches things up to a Rect. And here’s the really important part:
you can have as many Canvas elements in the scene as you wish.

Ok I think I have a solution that greatly minimizes overrides (see below - it may help others). The key is very heavy use of auto layout elements and making the parent an empty game object. This may be obvious but autolayout gets you three main benefits:

  1. Consistent appearance between editing as a prefab and inserting in the scene
  2. UI serialization bug less likely to appear in the first place
  3. When you “revert all” on your overrides in response to serialization bug you don’t lose your work. Worst case you remove the prefab and put it back into the scene.

Remaining questions

  • What do you think about a script at the prefab level (e.g. ShopUI.cs) to consistently reset the text fields (e.g. button text) to have it always say what you want it to? If overrides are accidentally removed, this can add them back in.
  • My buttons seem to create lots of “useless overrides” when the Shop UI prefab gets placed inside the UI Canvas prefab. This mainly seems to impact button’s RectTransform and the scroll bar. What I mean by “useless” is that when I revert it, nothing happens. Makes it hard to tell if I have a problem or not.

How I did the rest. This could be useful for many people.

  1. Parent with expanded prefab. Note how the parent has nothing in the inspector besides a rect transform.

  2. Scroll View: Apply the following settings to your scroll view so it expands to fit empty space. If everything else has some kind of autolayout, this will work.
    image

  3. Key Piece: The panel

  • The panel should be a child game object of the parent. Panel will look like this. Note how it stretches to fill the entire space of the parent. The parent should not be the panel.
    image
  1. All buttons have a content size fitter (set both horizontal and vertical fit as preferred) and a vertical layout (or horizontal) group. Buttons now resize to fit the text within them.
1 Like

Another thing I will add to all of this is… the resolution on your Canvas Scaler is VITAL to get right. If you’re aiming for a Landscape game, I personally recommend the reference resolution be Full HD. Most displays are going to either have the same aspect ratio (roughly 16:9), and if you anchor correctly (things to the right anchored to the right, things on the left anchored to the left) with a goodly amount of whitespace in the middle, you’ll avoid a LOT of headache…

Note that this means rebuilding the Inventory prefabs, which were scaled to a fat tablet resolution and do NOT scale correctly to other sizes.

100% agree. In my case I target 2048x1536 because I want to make sure it looks good on an ipad mini in landscape. The extra res on the sides is a bonus in my case.

Can you add more to this? What problem do you solve (or what gets easier) with multiple Canvas elements? I imagine you have one problem of needing to make sure they all have the same Canvas scaler.

TIL if you put your buttons under a parent with a Vertical Layout Group or Horizontal Layout group and “control child size” you don’t need a content size fitter on the button itself. It seems to do the exact same thing.

The MegaCanvas used in the course has too many nested prefabs and the serialization system just messes up, doesn’t crawl deep enough, etc.
When working with one canvas for each panel (or panel set, as I do leave Equipment and Inventory on the same Canvas, they are directly related!), you don’t risk messing up the other panels. The only thing you have to worry about is THAT canvas and it’s single menu.

I make sure that scaler is identical for each Canvas, and that they have an appropriate Raycaster.

That’s correct. Many roads to the same path, there are.

I did notice that when I work with my shop UI (or whatever UI panel set) prefab in prefab mode, it is easy to work with, even though it itself has nested prefabs. I haven’t added a canvas component to it yet.

So once each panel /panel set has a canvas under the transform, what object in the scene hierarchy do you put each panel / panel set under? Does each sit under core?

Yep. But once it’s under Core, I never touch it within the Core Prefab or within the scene, only edits I allow myself are in the prefab for that item (like ShopUI, for instance is only edited within the ShopUI prefab, in Core, it’s just there, no touchy!

Brilliant. I will try this later and report back.

I tried it. Few observations

  • The approach of two canvases seems to break Unity’s rendering order in scene view.
  • In game view (but not play mode), the content from the other canvas always seems to render behind anything from another canvas no matter what order in scene hierarchy it sits in.
  • In play mode, the two canvases render in unpredictable orders. You never get the jumbled mess from scene view. But if one needs to render some piece of UI on top of an other piece of game UI, I wouldn’t know how to do it. For example I would always need to render inventory, shops or dialogue over the persistent quest overlay I have in my top left.

The “sort order” field on the Canvas component seems to fix all of the above. But it has revealed another issue.

The UI behaves differently between edit and play mode. I have figured out this issue too I think - the root cause seems to be that sometimes autolayout groups do not “run”. I can “fix” it by running a cycle of show/hide.

I also heard of people having to run “LayoutRebuilder.ForceRebuildLayoutImmediate(recttransform of the layoutgroup);” via code. I think the solution is to reduce my reliance on autolayout groups. A quick google search reveals that they are very buggy, especially when nested.

  1. Edit Mode (below)

  1. Play Mode and clicking button for “show” (below)

  1. Play Mode and cycling show/hide twice (below)

Understatement of the week.

Scene View is just annoying for the developer. :slight_smile: I had a script some time back, (which of course I cannot find!) which when a given window is opened (in play mode), it automatically changes the sort order of that window, and saves a static index of the lastOpenedWindowSortValue. So if the inventory window had a sort order of 10 and the store had a sort order of 5, but I open the store while the inventory window, then the sort order on the store becomes 11, and then if I open the Inventory, it becomes 12, etc.

Now that I haven’t encountered. Or if I did, it was long enough ago that I just fixed it and forgot it…
My shop puts the Switch button at the bottom with the Buy button, and the X is anchored to the exact corner of the shop.

There seem to be a few layered issues

  1. If you have a horizontal or vertical layout group with only a single item in it, Unity seems to do very weird things. Even weirder if you don’t use “control child size”. Unity seems to ignore the (some parts of) a layout group on the initial rendering pass if it has only has a single element. Adding blank pixel with flexible width or height and enabling control child size seems to fix some of the problem
  2. But if you have too many nested layout groups it still seems to “ignore” some parts of the highest parent levels. For example it just ignored the spacing and margins of my top level vertical layout group but honored the rest of the layout group. I had to cycle through a full show/hide to get it honor the full layout group.

The trick now seems to be reduce reliance of nested layout groups. See below.

In response to seeing how buggy they are and this article from Unity… My latest idea was to do something like the following:

  • canvas per UI prefab, with a canvas scaler
  • game object / panel below it that is sized and anchored appropriately
  • while designing lay out everything with auto layout groups (e.g. vert and horizontal layout groups)
  • then remove all layout groups once happy with it (exception: dynamic content such lists inside scroll views)

I tried it and it looks like it may work. A major piece here is to remove the prefab from the scene, then edit in prefab mode, then add it back to the scene. Editing the prefab in the context of a scene will cause unpredictable results.

I’m not real thrilled with the edit in context. It can give you a false impression of what’s going on. That even applies to editing characters in context. I make a point of hitting Select (at the top of the inspector), then opening the prefab directly from the assets (where it will never be in context).

Now the the “best” solution… Converting your UI to UI Elements. Using elements, with each panel it’s own Document, you can achieve even greater control, but… it’s VERY time consuming to write a UI Elements panel properly (i.e. making it actually function).

For a great example (non-functional, because I’ve never pushed the assets to this repo and never will, just the code), check out this repo Spellborn GitLab and look at the code in Assets/TkrainDesigns/UIElements

All of the Course panels are reproduced as elements, including features such as pushing the most recently opened window to the front. The Dragging and Dropping is a mess, because Elements won’t accept our solution out of the box, I had to write a custom one that works right up until it doesn’t.

Here’s a sample of the UI Elements working: https://www.youtube.com/watch?v=6yUNf2mS6aE&lc=UgxF69DHwVgav9zjwdR4AaABAg

1 Like

Thanks.

UIElements sounds like the way to go. Maybe that’s V2 (or V10) for me. I’m gonna say what I have with the standard UI is “close enough.” The trick with putting everything in a separate Canvas and trying to avoid Auto Layout Groups will have to do.

What are you referring to when you say “our solution”?

Our Drag scripts don’t work with UI Elements. So I had to write a new set of scripts for handling dragging.

Ah got it. It was hard to map any one thing a solution since there appear to be so many quirks with UI in Unity.

If you’re using 2022.3x, UI is just the start of your quirks issues. :stuck_out_tongue:

I am. I encountered a few with some of the unexpected behavior changes in the dialogue course. And I’ve been getting spurious messages to the log (various out of memory warnings) ever since I did the turn based strategy course. And I get random ArgumentNullExceptions when I edit SOs.

oh and every now and then some operations seem to take forever on the first run through in play mode, making me believe I need some sort of background process to warm up the system.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms