Optimized screens using new UI: SetActive() vs. nested Canvases vs. nested CanvasGroup

Hi,

Our game is 100% based on the new UI. I want to know your opinion about best performant optimized solution to make menus and screen transitions using the new UI.

Our original solution:

A root GameObject with a single Canvas + GraphicRaycaster. Child objects are game screens.
Per game screen, I am using a root GameObject with a custom PanelScript and an animator for opening and closing animations. The animations are simple we just translate the screen panel in and out of the screen in one of the 4 directions using RectTransform’s anchors.

After profiling, I realized that the animator is being (re)initialized every time I (re)activate the GameObject to which it is attached. The first time an animator instance is initialized takes longer than subsequent ones for same animator type as I guess there are some IO/serialization operations being done under the hood. So I was thinking I should have this executed during splash screen.
Other than the animator’s initialization, we decided to remove as many [H/V]Layout as possible and merge as many Text components as possible.

Now we came up with 3 different approaches to do more optimization and would like to know your opinion:

  1. All screen GameObjects are active by default in the scene and will be deactivated once the first screen (splash) is opened. Toggle GameObject screens: SetActive(true) when a screen is about to be opened and SetActive(false) for the closed screen.
  2. Keep all screen GameObjects active in the scene, have a disabled Canvas per screen (a GraphicRaycaster is required per Canvas, top one is removed though). Toggle Canvas: canvas.enabled=true when a screen is about to be opened and canvas.enabled=false for the closed screen.
  3. Keep all screen GameObjects active in the scene, have a CanvasGroup with alpha=0f per screen. Toggle CanvasGroup: canvasGroup.alpha=1f when a screen is about to be opened and canvasGroup.alpha=0f for the closed screen.

From my having all your Canvases in one Scene is kind of nice and resorce-wise seems to have very little affect. Mainly because when you SetActive it disables the object and stops all code attached to it, making it SUPER convenient to hook into the OnEnable event. OnStart is great for initial stuff, but you’ll get the OnEnable/Disable on every SetActive.
The biggest issue I’ve seen is keeping it organized while you make new UI elements.
For a while I was just making UI prefabs, but it became easier to ensure object positions with leaving it In-Scene and enabling/disabling. Of course you’ll run into problems like your Animator, but even has you said, the additional loads reduce the time it takes. Perhaps you could keep the animator active elsewhere, and pass the reference to it as needed?

I’m not sure if this helps or is even the proper way to doing it, I’m a novice at this stuff at best, but one method I’m using is that each canvas has panels, that can be set active by code. I have other canvases that have their own camera assigned to them and I have two game manager objects, one that tracks which canvases & panels are set active and another that tracks which cameras are set active… we have a lot of tis going on something like 21 cameras and about as many canvases with sub panels, some of the panel’s are animated so there is a game object that tracks and enables the animations too… but it seems to work very well, but as I say i’m not sure if that is the recommended method, it’s pretty much just what I’ve cobbled together ;)… but hey it works like a dream near as I can tell :slight_smile: